策略模式的实际应用

版权声明:文章版权归作者所有,未经同意严禁转载! https://blog.csdn.net/sdksdk0/article/details/85067558

---------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处] 
文章出处:https://blog.csdn.net/sdksdk0/article/details/85067558

作者:朱培      ID:sdksdk0     
--------------------------------------------------------------------------------------------

应用场景:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独
立于使用它的客户而变化。

特点 :行为型模式 最终执行结果是固定的。执行过程和执行逻辑不一样。

目前在公司的实际项目中,有如下场景:有3中数据来源的详情查询(客流数据、舆情数据、画像数据),这三种数据请求的参数都是相同的,如参数里面都是省、市、县、景区名称、开始时间、结束时间。返回的数据也是相同的,都是分页返回一个map集合。然后前端通过type的不同分别查询不同的数据。在这个场景中,我们可以运用策略模式,将三种数据源封装,实现同一个接口,并且可以互相替换。

1、创建一个接口

public interface ISourceStrategy {
	
	public Map<String,Object> selectSourceByPage(Page page, String province, String city, String county,
			String name, String beginTime, String endTime);

}

2、创建实现接口的实体类。这里是3种不同的数据源详情查询

客流数据详情查询类,实现了前面的ISourceStrategy接口,这里的component名称为probeSourceDetail:

因为我的业务里面使用的mongodb,使用导入了MongoTemplate,这里按需写入自己需要的业务代码就行

@Component("probeSourceDetail")
public class ProbeSourceDetail implements ISourceStrategy{
	
	@Autowired
	private MongoTemplate mongoTemplate;
	
	@Override
	public Map<String, Object> selectSourceByPage(Page page, String province, String city, String county, String name,
			String beginTime, String endTime) {
		
		Map<String,Object> pageMap = new HashMap<String,Object>();
         //自己的业务代码,因为我的业务里面使用的mongodb,使用导入了MongoTemplate,这里按需写入自己需要的业务代码就行
		return pageMap;
	}

}

舆情数据详情查询,实现了前面的ISourceStrategy接口,这里的component名称为commentSourceDetail:

@Component("commentSourceDetail")
public class CommentSourceDetail implements ISourceStrategy{
	
	@Autowired
	private CCommentMapper cCommentMapper ;
	
	@Override
	public Map<String,Object> selectSourceByPage(Page page, String province, String city, String county, String name, String beginTime,
			String endTime) {
		
		Map<String,Object> pageMap = new HashMap<String,Object>();
	    .....
		return pageMap;
	}

}

画像数据详情查询,实现了前面的ISourceStrategy接口,这里的component名称为drawSourceDetail:

@Component("drawSourceDetail")
public class DrawSourceDetail implements ISourceStrategy{

	@Autowired
	private SJdAnalysisMapper  jdAnalysisMapper;
	
	@Override
	public Map<String, Object> selectSourceByPage(Page page, String province, String city, String county, String name,
			String beginTime, String endTime) {

		Map<String,Object> pageMap = new HashMap<String,Object>();
        ...
		return pageMap;
	}

}

3、创建 Context 类。

@Service
public class SourceContent {
	
	private Map<String, ISourceStrategy> strategyMap = new ConcurrentHashMap<>();
   /**
     * 注入了Strategy接口的Bean
     * @param strategyMap
     */
    @Autowired
    public SourceContent(Map<String, ISourceStrategy> strategyMap) {
        this.strategyMap.clear();
        for (Map.Entry<String, ISourceStrategy> entry : strategyMap.entrySet()) {
        	this.strategyMap.put(entry.getKey(), entry.getValue());
        }   
    }
	 
   public Map<String,Object> selectSourceByPage(String type,Page page, String province, String city, String county,
			String name, String beginTime, String endTime){
	   return strategyMap.get(type).selectSourceByPage(page, province, city, county, name, beginTime, endTime);
   }

}

4、在controller中使用

 /**
		 * 数据来源详情查询
		 * @param province  省
		 * @param city  市
		 * @param county 区县
		 * @param name   景区名称
		 * @param beginTime  开始时间
		 * @param endTime  结束时间
		 * @param pageId  第几页
		 * @param limit  每页数量
		 * @param type  查询类型,probeSourceDetail:客流数据 commentSourceDetail:舆情数据  drawSourceDetail: 画像数据
		 * @return
		 */
		@RequestMapping("/sourceDetailStrategy")
		@ApiDoc(ResultModel.class)
		public Object commDetailStrategy(String province,String city,String county,String name,String beginTime,String endTime,
				String type,Integer pageId,Integer limit){

			if (StringUtils.isEmpty(province) || province.equals("全部")) {
				province=null;
			}
			if (StringUtils.isEmpty(city) || city.equals("全部")) {
				city=null;
			}
			if (StringUtils.isEmpty(county) || county.equals("全部")) {
				county=null;
			}
			if (StringUtils.isEmpty(name) || name.equals("全部")) {
				name=null;
			}
			if (StringUtils.isEmpty(type) || type.equals("全部")) {
				type="probeSourceDetail";
			}
			if (!StringUtils.isEmpty(beginTime) && !isValidDate(beginTime)) {
				return responseData(201, "开始日期格式错误,应为"+DateUtil.formatDate(new Date()));
			}
			if (!StringUtils.isEmpty(beginTime) && !isValidDate(endTime)) {
				return responseData(202, "结束日期格式错误,应为"+DateUtil.formatDate(new Date()));
			}
			if (!StringUtils.isEmpty(beginTime) && isValidDate(endTime) && DateUtil.parseDate(endTime).getTime()>new Date().getTime()) {
				return responseData(203, "结束时间不能大于当前时间"+DateUtil.formatDate(new Date()));
			}
			if (!StringUtils.isEmpty(beginTime) && isValidDate(endTime) && DateUtil.parseDate(endTime).getTime()<DateUtil.parseDate(beginTime).getTime()) {
				return responseData(203, "结束时间不能小于开始时间"+DateUtil.formatDate(new Date()));
			}
			if (limit==null || limit==0) {
				limit = 20;
			}
			int offset = 0;
			if(pageId != null){
				pageId=pageId<1?1:pageId;
			}else {
				pageId = 1;
			}
			offset = (pageId-1)*limit;
			Page page = new Page<>((offset / limit + 1), limit);
			//此次采用了策略模式
			return responseSuccess(sourceContent.selectSourceByPage(type, page, province, city, county, name, beginTime, endTime));

		}

总结:1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

猜你喜欢

转载自blog.csdn.net/sdksdk0/article/details/85067558