对于代码写到一定地步,肯定会遇到很多业务代码的繁琐的if else分支。简单的几个条件可以if else几个,但是一旦后面的条件越来越多,有没有更好的替代让代码看起来没那么臃肿。更好维护,而不是一个if一个if的看过去。
其实是有的,就是工厂模式加策略模式来替代成坨的if else。
一 设计模式理解
首先来分析一下主要用到的两个设计模式
工厂模式:实际上工厂模式写法很多,比如说根据产品还是工厂方法来区分简单工厂和工厂方法模式。
根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。用于封装和管理对象的创建,是一种创建型模式。
//简单工厂模式
//首先你要有一个工厂,这个工厂实际上有很多流水线,每个流水线做不同的产品:比如手机和平板
public class Factory {
public Phone make(String type) {
if(phoneType.equalsIgnoreCase("Phone")){
return new Phone();
}
else if(phoneType.equalsIgnoreCase("Ipad")) {
return new Ipade();
}
return null;
}
}
//第二步,定义流水线(抽象的,流水线要用到方法)
public interface Equipment{
void make();
}
//第三步,是流水线来具体实施每个产品流水线的方法(这个是实现具体的)
public class Phone implements Equipment{
public Phone () {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("make phone 智能手机 !");
}
}
public class Ipad implements Equipment{
public Ipad () {
this.make();
}
@Override
public void make() {
// TODO Auto-generated method stub
System.out.println("make ipad 平板电脑!");
}
}
我们今天用到的其实有点像是简单工厂模式,就是工厂是一个,但是生产的产品是不同的,对比的是工厂方法模式,工厂接口,多个工厂继承工厂接口,每个工厂其实调用的方法相同但是各自实现完全不同
参照一下这个文章关于工厂模式的
设计模式工厂模式
策略模式
说句实在话,策略模式和工厂模式的抽象工厂方法挺像的。
对比就是策略模式里面有策略角色和具体策略角色,对比抽象工厂是抽象工厂和具体工厂。但是有一个context上下文来维护具体策略角色的实现
这个有个博客不错可以看一下
策略模式介绍
//抽象的策略
public abstract class Strategy {
//算法方法
public abstract void algorithmInterface();
}
//具体实现的策略,毕竟光抽象不行,还要给各个情况具体的策略
public class ConcreteStrategyA extends Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略A实现");
}
}
public class ConcreteStrategyB extends Strategy {
@Override
public void algorithmInterface() {
System.out.println("策略B实现");
}
}
//上下文context,用来维护策略,实际要访问具体的策略要从context中获取
public class Context {
Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
//上下文接口
public void contextInterface() {
strategy.algorithmInterface();
}
}
//使用的时候创建有具体策略的上下文
public class Client {
public static void main(String[] args) {
Context context;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
二 使用工厂模式+策略模式来替代if else
前面讲到了工厂模式和策略模式是什么,大概的写法(工厂模式写的肯定不全,可以看一下我链接的文章来看一下更多的工厂方式,其实相当于同一个操作提供给更多实现方式,来适应不同的情况)
实际上,就是利用工厂模式生成管理不同的策略(在这一步,工厂类特别像策略模式里面的上下文环境context),定好策略(这个跟抽象工厂方法很像,但是又有很大不同,抽象工厂加一个方法,所有的实现的方法具体工厂都要实现,但是利用了策励模式就不同,工厂只管管理调用方法,真正要用到的都是策励来提供),然后实现不同的具体策略
可以这么说,策励模式解决了一个工厂模式的问题,“我有的,你们实现的都要有”,现在工厂只是提供一个使用策略的方法,不关心你制定多少个策略,每个策励有多少实现。解耦的同时,还做到开-闭原则:对扩展开放,对修改关闭
具体例子:
光说不练假把式,我这里是根据不同的操作查询资产来限制资产是否可以展出,有问题会给个错误码,同样也会把资产数据返回。
(1)创建工厂
工厂维护策略模式,以及具体实现的策略模式的注册,注册后的策略存在一个维护策略的map里面,适用工厂直接通过type类型作为code值来获取策略map里面的策略。
public class ValidAssetByTypeFactory {
private static Map<String,ValidateAssetService> validAssetTypeMap = new HashMap<>();
/**
* 用来维护根据类型验证资产的规则的map
* @param type
* @return
*/
public static ValidateAssetService getInvokeStrategyMap(String type){
return validAssetTypeMap.get(type);
}
/**
* 注册(创建实现类直接注册即可,不需要在该类放进策略map里面)
* @param type
* @param validateAssetService
*/
public static void register(String type, ValidateAssetService validateAssetService){
if(StringUtil.isEmpty(type)||null == validateAssetService){
return;
}
validAssetTypeMap.put(type,validateAssetService);
}
}
(2)创建策略
这个就直接解耦工厂模式的,“我有你们都要有“。策励是一个接口,具体策略就是实现这个接口,在策略模式里面,可以直接获取实现的具体策略。
注意点就是这个 extends InitializingBean不能少,全靠这个往工厂类里面的静态map里面塞值呢。
以下是一个例子,实际上肯定会有很多实现的具体策略。
/**
* 关于扫码验证资产的策略接口
* @Author: zhangpeng
* @Date: 2021/9/9 13:49
*/
public interface ValidateAssetService extends InitializingBean {
Result<List<DetailsAppAsset>> validateAssetByType(List<AssetDO> assetDOList,String type);
}
(3)具体的实现策略
这个就根据实际情况来实现,造火箭用造火箭的制造方法,造螺丝用造螺丝的方法。
@Component
public class RepairAssetValidate implements ValidateAssetService {
@Override
public Result<List<DetailsAppAsset>> validateAssetByType(List<AssetDO> assetDOList, String type) {
if( CollUtil.isEmpty(assetDOList) ){
return resultCreator.create(AssetErrorCode.ASSET_NOT_EXISTS, EntityConverter.convertList(assetDOList, DetailsAppAsset.class));
}
for(AssetDO assetDO : assetDOList){
if( assetDO.getQuoteOrderId() != null ){
return resultCreator.create(AssetValidErrorCode.ASSET_IN_OTHER_OPERATOR,"资产已被"+ QuoteOrderType.getQuoteOrderType(assetDO.getQuoteOrderType())+"引用" ,EntityConverter.convertList(assetDOList, DetailsAppAsset.class));
}
}
return resultCreator.create(ErrorCode.SUCCESS, EntityConverter.convertList(assetDOList, DetailsAppAsset.class));
}
@Override
public void afterPropertiesSet() throws Exception {
ValidAssetByTypeFactory.register(AssetValidateType.REPAIR.getValue(),this);
}
@Autowired
private ResultCreator resultCreator;
}
(4)做一个维护策略的枚举
其实这个可以不做,直接用字符串来获取策略map里面的具体策略也可以。
但是考虑到要管理起来,别最后起名没有规范,重名,或者不知道到底有多少相关的策略,实际上通过枚举管理起来挺好的,你想绕过这一步也是了可以的,毕竟不是强相关的一步。
public enum AssetValidateType implements StringOption {
ALLOCATE("allocate"),
BATCH_UPDATE_ASSET("batchUpdateAsset"),
UPDATE_BY_RESIDUAL("updateByResidual"),
CHANGE_USER_ASSET("changeUserAsset"),
BACK_ORDER("backOrder"),
BORROW_RETURN("borrowReturn"),
BORROW("borrow"),
COLLECT("collect"),
DISPOSE("dispose"),
RECYCLE("recycle"),
REPAIR("repair")
;
private String value;
AssetValidateType(String v){
setValue(v);
}
@Override
public void setValue(String value) {
this.value = value;
}
@Override
public String getValue() {
return this.value;
}
@Override
public boolean equals(String i) {
return this.getValue().equals(i);
}
}
好了这样就是一个完整的工厂模式+策略模式替代if else的方式
好处是代码看起来更简洁,不再是一大堆if else,而且方便扩展,不必扩展一个业务条件就写一个if的条件限制。
坏处是如果不是很复杂的业务这么写,会有设计过度的情况,对代码读写理解有一定要求,肯定没有入门那种if else方便看懂(其实shiro这些框架具有类似的设计,我当时看授权的这部分就很懵,不能直接debug一个一个往下跳,你要找最后实现的部分才能最后找对地方debug)