一起学之 《工厂模式+策略模式解决if-else过多问题》

起因:

最近写的业务if-else判断过多,对代码的可读性和维护性都带来了很大的困难,因此想着对之前的代码重构一下。

代码类似如下:

      if (){
            if (){

            }else if(){

            }
        }else if(){
            if (){

            }else if(){

            }
        }else if(){
            if (){

            }else if(){

            }
        }

解决方案:

解决方案有很多种,我这里选择的是工厂+策略模式。当然最重要的一点是,很多if else如果不是特别复杂没必要重构,不要为了用而用,这样会增加代码的维护量,适得其反。

如果不知道策略模式的可以看我之前写的文章,本文也是根据那篇文章进行进一步的扩展。
一起学之 《设计模式-策略模式》

为重构的代码如下:

//计算所交税
public class PayTaxes {

    private String name;
    private double money;

    public PayTaxes(String name,double money){
        this.money = money;
        this.name = name;
    }

    public double calculate(){
        if(name.equals("China")){
            return money * 0.2;
        }else if(name.equals("USA")){
            return money * 0.3;
        }else {
            return money * 0.33;
        }
    }
}
//测试类
public class Test1 {
    public static void main(String[] args) {
        PayTaxes payTaxes = new PayTaxes("China",10000);
        double taxes =  payTaxes.calculate();
        System.out.println("中国应交所得税为:"+taxes);

        PayTaxes payTaxes2 = new PayTaxes("USA",10000);
        double taxes2 =  payTaxes2.calculate();
        System.out.println("美国应交所得税为:"+taxes2);

        PayTaxes payTaxes3 = new PayTaxes("Japan",10000);
        double taxes3 =  payTaxes3.calculate();
        System.out.println("日本应交所得税为:"+taxes3);
    }
}

我们可以看到上面的calculate() 方法中有非常复杂的if else(当然不复杂,完全没必要改变或者改成switch可能更直观。这里我们就当很复杂来处理)。下面我们先通过策略模式做一下修改。

//抽象策略
public interface PayTaxesStrategy {
    double calculate(int money);
}

//具体策略中国
public class PayTaxesConcreteStrategyChina implements PayTaxesStrategy {

    @Override
    public double calculate( int money) {
        return money * 0.2;
    }
}

//具体策略美国
public class PayTaxesConcreteStrategyUsa implements PayTaxesStrategy {

    @Override
    public double calculate(int money) {
        return money * 0.3;
    }
}


//具体策略日本
public class PayTaxesConcreteStrategyJapan implements PayTaxesStrategy{

    @Override
    public double calculate(int money) {
        return money * 0.33;
    }
}


//测试类
public class Test1 {
    public static void main(String[] args) {
        PayTaxesStrategy payTaxes = new PayTaxesConcreteStrategyChina(10000);
        double taxes =  payTaxes.calculate();
        System.out.println("中国应交所得税为:"+taxes);

        PayTaxesStrategy payTaxes2 = new PayTaxesConcreteStrategyUsa(10000);
        double taxes2 =  payTaxes2.calculate();
        System.out.println("美国应交所得税为:"+taxes2);

        PayTaxesStrategy payTaxes3 = new PayTaxesConcreteStrategyJapan(10000);
        double taxes3 =  payTaxes3.calculate();
        System.out.println("日本应交所得税为:"+taxes3);
    }
}

如上所示我们已经通过策略模式进行了改变,但是正常的业务Text1类不能这样写应该如下:

public class Test1 {
    public static void main(String[] args) {
        String name = "China";
        if(name.equals("China")) {
            PayTaxesStrategy payTaxes = new PayTaxesConcreteStrategyChina(10000);
            double taxes = payTaxes.calculate();
            System.out.println("中国应交所得税为:" + taxes);
        }else if(name.equals("Usa")) {
            PayTaxesStrategy payTaxes2 = new PayTaxesConcreteStrategyUsa(10000);
            double taxes2 = payTaxes2.calculate();
            System.out.println("美国应交所得税为:" + taxes2);
        }else {
            PayTaxesStrategy payTaxes3 = new PayTaxesConcreteStrategyJapan(10000);
            double taxes3 = payTaxes3.calculate();
            System.out.println("日本应交所得税为:" + taxes3);
        }
    }
}

我们可以从上面发现,我们虽然解决掉了calculate() 中的if-else。但是在选择策略的时候我们又用了if-else,兜兜转转又回到了起点。所以需要增加一个工厂类来帮我们选择策略。

代码如下:

public class GetContryFactory {

    private static Map<String, PayTaxesStrategy> request = new ConcurrentHashMap<String, PayTaxesStrategy>();

    public  static PayTaxesStrategy getByRequestType(Integer type){
        return request.get(type);
    }

    public static void register(String name,PayTaxesStrategy spRequest){
        request.put(name,spRequest);
    }
}

//此时的Test1
public class Test1 {
    public static void main(String[] args) {
        String name = "China";
        GetContryFactory.register("China",new PayTaxesConcreteStrategyChina());
        GetContryFactory.register("Usa",new PayTaxesConcreteStrategyJapan());
        GetContryFactory.register("Japan",new PayTaxesConcreteStrategyUsa());
        PayTaxesStrategy payTaxesStrategy = GetContryFactory.getByRequestType(name);
        payTaxesStrategy.calculate(10000);
    }
}

我们通过一个Map去存储我们所有的策略实体类,用条件作为key,策略类作为value,要一一对应。先是在程序启动的时候认为的为我们的Map添加数据,通过调用register() 方法。然后通过工厂的getByRequestType() 方法去map中获取策略类对象(工厂代替我们生产对象)。这就是工厂+策略模式去解决if-else嵌套过多的问题。

但是我想大家应该发现了一个问题,就是我们每次都需要去手动的维护我们的Map非常麻烦,我们可以通过Spring InitializingBean 接口并重写 afterPropertiesSet 方法,将策略实现注册到工厂类 map 中。

修改策略实现类,如下只列出一个其它类似。

代码如下:

@Service
public class PayTaxesConcreteStrategyChina implements PayTaxesStrategy, InitializingBean {

    @Override
    public double calculate( int money) {
        return money * 0.2;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        GetContryFactory.register("China",new PayTaxesConcreteStrategyChina());
    }
}

至此整个项目结束,我这里还有一个contex分装类没有写,大家可以类比我之前的策略模式自行增加,工厂类返回 context,context 包住 策略实现。

git地址

git项目地址

启动项目输入localhost:8080即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值