本系列总结的设计模式,皆在实际的生产项目中有实际的运用,实例也皆为项目中的例子。
场景:
需要将net 项目中的一个推荐接口,迁移到java 。
推荐接口的内容是根据不同的类型做出不同的推荐,历史的net代码冗余太多,大概有7,8个if...呈现在主方法里。每个if里有在相应的biz类中有对应的业务代码。
如果有新的类型推荐,则会在主方法里新增一个if()...然后再相应的biz 里写业务代码。
if (request.type = "A") { //recommend plane return response; } if (request.type = "B") { //recommend bus return response; } if(request.type = "R") { //recommend round plane return response; } // C,X ....
形成原因:
相信所有的业务系统都会有类似的代码,新增一个类型,用if()..可以快速实现逻辑。这样也没有什么问题。
自己也分析了下,为什么业务系统代码普遍代码质量不高的原因。
1.逻辑需要快速实现,怎么方便怎么来
2. 整体的业务系统没有定义一个清晰的代码规则和编码约束。
3. coder的技术水平层次不齐。
迁移改造:
这种场景决定用抽象工厂去做相应的改造,根据不同的recommendType 来做出相应的推荐。每种type对应有自己的实现子类.
Factory类 根据recommenType 去找到对应的子类。
/** * Created by liyangyang on 2017/10/18. */ @Service public class RecommendInfoFactory implements IRecommendInfoFactory { @Autowired @Qualifier("A") private RecommendInfoOfTypeA recommendInfoOfTypeA; @Autowired @Qualifier("B") private RecommendInfoOfTypeB recommendInfoOfTypeB; @Autowired @Qualifier("Default") private RecommendInfoOfTypeDefault recommendInfoOfTypeDefault; @Autowired @Qualifier("H") private RecommendInfoOfTypeH recommendInfoOfTypeH; @Autowired @Qualifier("NJSH") private RecommendInfoOfTypeNJSH recommendInfoOfTypeNJSH; @Autowired @Qualifier("R") private RecommendInfoOfTypeR recommendInfoOfTypeR; @Autowired @Qualifier("X") private RecommendInfoOfTypeX recommendInfoOfTypeX; @Autowired @Qualifier("KT") private RecommendInfoOfTypeKongTie recommendInfoOfTypeKongTie; @Override public IRecommendInfo getInstance(String recommendType) { IRecommendInfo recommendInfo; //根据推荐类型,判断推荐内容 switch (recommendType){ case "A": recommendInfo = recommendInfoOfTypeA; break; case "B": recommendInfo = recommendInfoOfTypeB; break; case "H": recommendInfo = recommendInfoOfTypeH; break; case "R": recommendInfo = recommendInfoOfTypeR; break; case "X": recommendInfo = recommendInfoOfTypeX; break; case "NJSH": recommendInfo = recommendInfoOfTypeNJSH; break; case "KT": recommendInfo = recommendInfoOfTypeKongTie; break; default: recommendInfo = recommendInfoOfTypeDefault; break; } return recommendInfo; } }
推荐的主方法:
public GetRecommendListResponseType getRecommendList(GetRecommendListRequestType request) { //根据不同的recommendType 去找到对应的实现子类 IRecommendInfo recommendInfo = recommendInfoFactory.getInstance(request.getRecommendType()); //调用实现子类的逻辑得到对应的推荐 GetRecommendListResponseType response = recommendInfo.getRecommend(request, cityInfo, distance, addition); return response; }
相应的实现子类 A , B , C 。。。:
/** * Created by liyangyang on 2017/10/18. */ @Service @Qualifier("A") public class RecommendInfoOfTypeA implements IRecommendInfo{ @Autowired private IGetRecommendListCommonBiz getRecommendListCommonBiz; @Override public GetRecommendListResponseType getRecommend(GetRecommendListRequestType request, RecommendInfoOfCityEntity cityInfo, double distance, HashMap<String,String> addition) { GetRecommendListResponseType responseType = new GetRecommendListResponseType(); List<RecommendInfo> recommendInfos = Lists.newArrayList(); //推荐机票 RecommendInfo recommendInfo = getRecommendListCommonBiz.getRecommendPlane(request, cityInfo, distance,addition); if (!Objects.isNull(recommendInfo)) { recommendInfos.add(recommendInfo); responseType.setRecommendList(recommendInfos); } return responseType; } }
优点:
1. 相比 net 中的 if()... 形式,每个子类都对应自己的职责,职责和对应的代码结构更清晰。
2. 新增一个recommendType, 只需新增对应的实现子类。基本满足对扩展开放,对更改封闭。
缺点:
1. 类文件太多。
2. 新增一个recommendType, 还需要在Factory类中,新增一个case 来实现子类的路由。没有满足更改封闭。
改进:
1. 用抽象工厂 + 反射 来自动路由相应的子类。但反射对应的效率会是个瓶颈。
PS: java 中的多态实现:一个接口对应不同的实现。比如A,B,C 实现同一个接口。
java 中spring boot 容器是以接口的形式注入到容器中的。 默认是一个接口只有一个实现类。这样自动装配的时候,就会默认去找到接口对应的实现。
但如果 一个接口有N个子类实现,spring boot 容器装配的时候就会出错。因为它不知道去装配那个子类。
在相应的子类上添加 @Qualifier("A") 注解注入,装配的时候也加上 @Qualifier("A") 。
对应解释: https://www.cnblogs.com/smileLuckBoy/p/5801678.html