java策略模式去掉冗余if-else实战支付案例

java策略模式去掉冗余if-else支付案例实战

前言

上一篇文章介绍了 java中冗余if-else代码块的优化(策略模式法,反射法)
,里面详细介绍了策略模式+工厂模式来解决代码中大量的if-else结构。

这一篇就举个实战例来说明,怎么使用策略模式。

1.支付案例需求

假设你在做的某个项目,需求就是页面选择不同的付款渠道,计算不同的折扣,进行扣款。
在这里插入图片描述
看到这个图片,有小伙伴在遇到诸如此类的需求的时候,想到的会是,很简单,if else 判段下就可以了嘛,if else 确实可以解决我们的问题,但是弊端也很明显:

  • 代码冗长
  • 维护不便

谁叫我们学习过了策略模式+工厂模式来解决代码中大量的if-else结构呢?
在这里插入图片描述

2.策略设计模式干掉if-else(通用写法)

策略模式+工厂模式解决代码中大量的if-else结构的(通用写法),以后遇到多条件的业务需求,就直接可以复用了。

文件目录:
在这里插入图片描述

1.定义充值支付的枚举类

RechargeTypeEnum.java 源码如下:

package PayDemo;
/**
 * @Description: 1.定义枚举类型
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public enum RechargeTypeEnum {
    /**
     * 枚举类型,根据业务需求增删
     */
    ABC_BANK(1,"农业银行"),
    ICBC_BANK(2,"工商银行"),
     /*根据自己到底业务需求增加个数*/
    CCB_BANK(3,"建设银行"),
    CMB_BANK(4,"招商银行"),;

    /**
     * 状态值
     */
    private int code;

    /**
     * 类型描述
     */
    private String description;
    RechargeTypeEnum(int code, String description) {
        this.code = code;
        this.description = description;
    }

    public int getCode() {
        return code;
    }
    public String getDescription() {
        return description;
    }
    // 根据code获取对应的枚举类型
    public static RechargeTypeEnum getPayTypeEnum(int code) {
        for (RechargeTypeEnum calcTypeEnum : RechargeTypeEnum.values()) {
            if (calcTypeEnum.getCode() == code) {
                return calcTypeEnum;
            }
        }
        System.out.println("对应支付计算策略不存在,[type={\"+code+\"}]");
        return null;
    }
}

2.定义支付的计算策略接口类

PayStrategy.java:

package PayDemo;
/**
 * @Description: 2.定义支付的策略接口类
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public interface PayStrategy {
    /**
     * 策略行为方法:定义根据金额进行结算的方法
     * @param charge
     * @param type
     * @return
     */
    public Double calRecharge(Double charge ,RechargeTypeEnum type);
}

3.定义多个结算渠道具体的结算实现类

创建实现类的数量视自己的业务需求而定。

(针对每一类情况来分别实现上面接口,不是继承,是实现!!!
所以要在实现的方法中写好具体的计算规则代码。)

ABCPayStrategy.java
ICBCPayStrategy.java
CCBPayStrategy.java

比如我们写一个农业银行的,一个工商银行的。

ABCPayStrategy.java代码如下:

package PayDemo;
/**
 * @Description: 具体有多少业务实现类,视自身业务而定
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public class ABCPayStrategy implements PayStrategy {
    /**
     * 农业银行的结算实现类
     * 优惠98折
     * @param charge 金额
     * @param type 支付类型
     * @return
     */
    @Override
    public Double calRecharge(Double charge, RechargeTypeEnum type) {
        return charge*0.98;
    }
}

ICBCPayStrategy.java代码如下:

package PayDemo;
/**
 * @Description:
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public class ICBCPayStrategy implements PayStrategy{
    /**
     * 这边就是具体业务代码的实现方法
     * 工商银行的结算实现类
     * 收取5元手续费
     * @return
     */
    @Override
    public Double calRecharge(Double charge, RechargeTypeEnum type) {
        return charge+5;
    }
}


实现类的数量视自己业务而定。

4.策略上下文类PayContext.java

作用就是根据类型路由到具体的实现类。
其中,创建接口的对象。
调用工厂类的getInstance和creator方法来路由到具体实现方法中。

package PayDemo;

/**
 * @Description: 4.策略上下文,作用就是根据类型路由到具体的实现类
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public class PayContext {
    
    // 创建接口的对象
    private PayStrategy strategy;

    public Double calRecharge(Double charge, Integer type) {
        try{
            strategy= StrategyFactory.getInstance().creator(type); // 调用工厂类的getInstance和creator方法
        }catch (Exception e){
            //log
            System.out.println("程序出错了!");
        }
        return strategy.calRecharge(charge,RechargeTypeEnum.getPayTypeEnum(type));
    }

    public PayStrategy getStrategy() {
        return strategy;
    }
    public void setStrategy(PayStrategy strategy) {
        this.strategy = strategy;
    }
}

5.建立工程模式类StrategyFactory.java,

工厂模式来批量创建我们需要的类型的对象。new ABCPayStrategy(),new ICBCPayStrategy()。。。

package PayDemo;

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

/**
 * @Description: 工厂模式-根据类型,把具体的实现类对象创建出来
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public class StrategyFactory {

    //生成工厂对象
    private static StrategyFactory factory = new StrategyFactory();
    private StrategyFactory(){
    }
    
    private static Map<Integer ,PayStrategy> strategyMap = new HashMap<>();
    static{
        //通过put或注解的方式把对象加载到map中
        strategyMap.put(RechargeTypeEnum.ABC_BANK.getCode(), new ABCPayStrategy());
        strategyMap.put(RechargeTypeEnum.ICBC_BANK.getCode(), new ICBCPayStrategy());
        strategyMap.put(RechargeTypeEnum.CCB_BANK.getCode(), new CCBPayStrategy());
        /* 自行增加业务需求
        strategyMap.put(RechargeTypeEnum.CMB_BANK.getCode(), new CardStrategy());...
        */
    }

    //工厂模式来创建我们需要的对象
    public PayStrategy creator(Integer type){
        return strategyMap.get(type);
    }
    //返回工厂对象
    public static StrategyFactory getInstance(){
        return factory;
    }
}

6.接口的测试类PayTest.java,

必须创建上下文对象,调用接口方法calRecharge计算策略,得到对应的需求结果。

package PayDemo;

/**
 * @Description: 上下文对象来调用对应的支付方式测试
 * @Author: Zoutao
 * @Date: 2020/4/10
 */
public class PayTest {
    public static void main(String[] args) {
    
        // 创建上下文对象来调用对应的支付方式
        PayContext context = new PayContext();

        // 农业充值100 需要付多少
        Double money = context.calRecharge(100D,
                RechargeTypeEnum.ABC_BANK.getCode());
        System.out.println(money);

        // 工商充值100 需要付多少
        Double money2 = context.calRecharge(100D,
                RechargeTypeEnum.ICBC_BANK.getCode());
        System.out.println(money2);
        
        // 新增-建设银行充值方式
        Double money3 = context.calRecharge(100D,
                RechargeTypeEnum.CCB_BANK.getCode());
        System.out.println(money3);
    }
}

以上就完成了一个策略模式+工厂模式的通用代码结构,在文章解决掉了所有的if-else结构,优化了代码,有利于后期的维护。

7.如果要新增一个新功能业务?

–以新建一个建设银行支付渠道为例。
(只需要新增代码而不需要修改原代码。这样设计程序的好处就体现出来了。)

a.首先在枚举类RechargeTypeEnum中新增类型和描述。

CCB_BANK(3,“建设银行”),

b.在增一个对应接口实现类CCBPayStrategy。
定义具体的接口方法内容。

package PayDemo;
public class CCBPayStrategy implements PayStrategy {
    /**
     * 建设银行实现类
     * 优惠96折
     * @param charge
     * @param type
     * @return
     */
    @Override
    public Double calRecharge(Double charge, RechargeTypeEnum type) {
        return charge * 0.96;
    }
}

c.然后在工厂类StrategyFactory当中添加,生成对应的类对象和枚举类型。

strategyMap.put(RechargeTypeEnum.CCB_BANK.getCode(), new CCBPayStrategy());

d.最终在PayTest调用即可。

  // 新增-建设银行充值方式
  Double money3 = context.calRecharge(100D,
        RechargeTypeEnum.CCB_BANK.getCode());
  System.out.println(money3);

结果:
在这里插入图片描述

至此我们业务功能就完成了,可能大家会觉得,设计模式的引入反而造成了类太多,还不如直接if else写在一个文件里的直观。

但是,对于后期的程序开发中,如果要新增一个付款渠道,使用策略模式的方式将变得很简单,只要定义一个具体的实现类,加上对应的工厂对象调用就解决了,根本不需要去阅读之前别人写的其他支付渠道的代码,松耦合的目的就在于此。


参考地址:
注解版:https://zhuanlan.zhihu.com/p/33383648
https://www.iteye.com/blog/alaric-1920714
https://blog.csdn.net/u014395955/article/details/103804479
https://www.toutiao.com/i6813584351410782723/

发布了212 篇原创文章 · 获赞 934 · 访问量 106万+

猜你喜欢

转载自blog.csdn.net/ITBigGod/article/details/105443276