使用策略模式代替繁琐的if else

前言

这两天在知乎上看到一篇文章名叫《一个程序员的水平能差到什么程度?》这上面写的代码确实让看的人当做饭后笑话的谈资,让下一个接盘的人又磨刀霍霍向猪羊的冲动
在这里插入图片描述
里面大部分的吐槽都是针对于if else 无作为的使用以及滥用的吐槽,if …else if … else…这确实是我们在各种项目研发中的一个利器,但是一旦他过于多,就会使逻辑混乱,让代码的可读性大大下降,并且我发现在我以前写的项目中也存在许多的if…else…因而我下定决定,画了一天时间研究,打算使用策略模式来代替过多的if else。

策略模式的介绍

策略模式
引入百科的解释:策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。

策略模式:顾名思义就是当要在不同的情况下做出该情况下所适用的策略,按照面向对象的是思想就是,就使用继承和多态机制,实现同一行为在不同场景下具备不同实现。

策略模式的本质:分离算法,选择实现。

主要解决

从上述的策略模式的本质中的选择实现是不是可以联想到if…else if… else…没错,在有多种算法相似的情况下,使用 if…else 或 switch…case 所带来的复杂性和臃肿性。

优缺点

优点

  • 策略的多样性,能够自由切换
  • 有效的避免了多重判断,提高了代码的可读性,扩展性,封装性
  • 降低了操作难度以及错误率。

缺点

  • 增加了开发难度,策略类数量增多,并且所要策略类都要对外开放,以便客户端访问

你还在用if else吗?

这里给大家举一个典型的例子
我们每天扫码支付,选用支付方式,选择的微信,支付宝,或者是直接银行卡支付。想必大家已经屡见不鲜了。
那我们现在我们需要做一个支付系统,通过扫描二维码对一个商户进行付款,我们可以选用我们已经绑定的支付宝账号,微信,或者所绑定的银行,直接进行支付,由于每家商户不同,可能付款的时候可能也会有一些优惠政策的不同,并且他们为外界所提供的API也会有所不同。例如,支付宝可以使用红包进行抵用,直接使用银行卡付款,每家银行可能会有不同的折扣。具体情况比较复杂,这里就不做考虑,为了为接下来的策略模式做铺垫,我们这里就简单的分为,微信支付,支付宝支付,银行卡支付,抵用券支付。
我相信很多人拿到需求后,最先考虑的写法就是:

package pay;

public class Example {

    public String selectPayWay(Integer payCode){
        if(PayWayEnum.WEICHAT_PAY.equals(payCode)){
            //do something
            return "微信支付成功";
        }else if(PayWayEnum.AL_PAY.equals(payCode)){
            // do something
            return "支付宝支付成功";
        }else if(PayWayEnum.CARD_PAY.equals(payCode)){
            // do something
            return "银行卡成功";
        }else if(PayWayEnum.PONIT_COUPON_PAY.equals(payCode)){
            // do something
            return "优惠券支付成功";
        }else {
            return "";
        }
    }

}
 

可以看出上面四种不同的支付方式在同一个方法体内部,不利于扩展和维护,并且也不符合面向对象设计原则。对以上的代码使用策略模式进行代替,类图如下:

在这里插入图片描述
从 上面的UML 类图中,我们可以看到,策略模式 主要包含三种角色:

  • 上下文角色(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
  • 抽象策略角色(Strategy):规定策略或算法的行为;
  • 具体策略角色(ConcreteStrategy):具体的策略或算法实现;

java代码实现具体如下

package strategy;

public interface PayStrategy {
    String selectPayWay(Integer paycode);
}

规定具体策略行为

package strategy;

public class PayContext {

    private PayStrategy payStrategy;

    public String selectPayWay(Integer payCode){
        payStrategy =  StrategyFactory.getInstance().create(payCode);
        return payStrategy.selectPayWay(payCode);
    }

    public PayStrategy getPayStrategy() {

        return payStrategy;
    }

    public void setPayStrategy(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }
}

支付宝付款实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class ALPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "支付宝支付成功";
    }
}

银行卡支付实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class CardPayStrategy implements PayStrategy {
    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "银行卡支付成功";
    }
}

点券支付实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class PointCouponPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "点券支付成功";
    }
}

微信支付实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class WeChatPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "微信支付成功";
    }

}

创建策略类的工厂

package strategy;

import pay.PayWayEnum;
import strategy.paystrategy.ALPayStrategy;
import strategy.paystrategy.CardPayStrategy;
import strategy.paystrategy.PointCouponPayStrategy;
import strategy.paystrategy.WeChatPayStrategy;

import java.util.HashMap;
import java.util.Map;

public class StrategyFactory {

    private static StrategyFactory factory = new StrategyFactory();

    private StrategyFactory(){}

    private static Map strategyMap = new HashMap<>(16);

    static {
        strategyMap.put(PayWayEnum.AL_PAY.getCode(),new ALPayStrategy());
        strategyMap.put(PayWayEnum.WEICHAT_PAY.getCode(),new WeChatPayStrategy());
        strategyMap.put(PayWayEnum.CARD_PAY.getCode(),new CardPayStrategy());
        strategyMap.put(PayWayEnum.PONIT_COUPON_PAY.getCode(),new PointCouponPayStrategy());
    }

    public PayStrategy create(Integer payCode){
        return (PayStrategy) strategyMap.get(payCode);
    }

    public static StrategyFactory getInstance(){
        return factory;
    }

}

实现客户端

package strategy;

public class Client {

    public static void main(String[] args) {
        PayContext payContext = new PayContext();
        System.out.println(payContext.selectPayWay(100));
    }
}

最后在贴一个枚举类

package pay;

public enum PayWayEnum {

    /**微信支付*/
    WEICHAT_PAY("微信支付",100),
    /**支付宝支付*/
    AL_PAY("支付宝支付",101),
    /**银行卡支付*/
    CARD_PAY("银行卡支付",102),
    /**点券支付*/
    PONIT_COUPON_PAY("点券支付",103);

    private String msg;
    private Integer code;

    PayWayEnum(String msg, Integer code) {
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public Integer getCode() {
        return code;
    }
}

从上面代码中,我们可以看到,我们完全消除了对状态码进行判断的那些if…else的冗余代码,取而代之是直接由客户端决定使用哪种算法,然后交由上下文获取结果。极大的增强的了扩展性,隐藏了内部实现的细节,当然我们也可以看到,策略模式由于独立策略的实现,也使得系统内部增加了很多策略,对客户端来必须知道这些策略类实现的是那些策略,而且需要知道具体的策略条件。

然而在实际的生产环境中我们可能不会像示例代码这样干,在实际的生产环境中我们一般会结合spring来对我们所需的策略进行操作,这边我可以给大家有个具体的思路,大家可以通过这个思路来想想,自己在实际生产环境会怎样操作

整体思路:

  1. 首先和上面代码一样定义一个Strategy接口,其中有一个operation的函数交给具体业务去实现
  2. 根据自己的业务,会拥有很多的策略类实现该接口;将这些类注册到spring Bean容器中提供使用。
  3. 通过客户端传值,从spring容器中获取Strategy实例
  4. 最终来执行operation函数

好了这次的分享就到此结束啦,下次我在真正的开发项目中使用到了策略模式代替if else的话我会结合我的项目在给大家看下怎样在实际的生产环境中应用,感谢大家的阅读。

  • 10
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
是的,可以使用策略模式代替 if else 语句。策略模式是一种行为型设计模式,它定义了一系列的算法,并将每个算法封装起来,使它们可以相互替换。这样就可以在运行时动态地选择算法,而不必使用 if else 语句来判断。 下面是一个简单的例子,使用策略模式来计算商品的折扣价格: 首先,定义一个 DiscountStrategy 接口,其中包含一个计算折扣价格的方法: ```java public interface DiscountStrategy { double calculateDiscount(double price); } ``` 然后,实现几个具体的 DiscountStrategy 实现类,如 NoDiscountStrategy、FixedDiscountStrategy、PercentageDiscountStrategy。这些类分别表示不打折、固定金额折扣、百分比折扣等不同的折扣策略。 最后,在需要计算折扣价格的地方,使用一个 DiscountContext 来选择具体的 DiscountStrategy 实现类,并调用其 calculateDiscount 方法: ```java public class DiscountContext { private DiscountStrategy strategy; public DiscountContext(DiscountStrategy strategy) { this.strategy = strategy; } public void setStrategy(DiscountStrategy strategy) { this.strategy = strategy; } public double calculateDiscountPrice(double price) { return strategy.calculateDiscount(price); } } ``` 使用时,可以这样调用: ```java DiscountContext context = new DiscountContext(new PercentageDiscountStrategy(0.2)); double originalPrice = 100.0; double discountedPrice = context.calculateDiscountPrice(originalPrice); ``` 这样,就可以根据具体的折扣策略来计算折扣价格,而不必使用 if else 语句来判断。同时,如果需要添加新的折扣策略,只需要实现一个新的 DiscountStrategy 实现类,并在 DiscountContext 中设置即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值