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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章