利用工厂模式和策略模式来替代if else

对于代码写到一定地步,肯定会遇到很多业务代码的繁琐的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)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值