Spring boot 運用策略模式實現避免多次使用if的操作代碼

前言

這裡就不詳細去介紹策略模式是怎麼樣的瞭,想瞭解的可以點擊下面的鏈接

策略模式介紹的鏈接:策略模式的介紹

這裡列出策略模式的好處

場景:某網頁有個支付,其中包含瞭微信、支付寶等方式的支付方式 ,後續明確還會進行兼容其他的支付方式

用策略模式的好處:

  • 避免多次使用if判斷具體是用哪種支付策略進行操作。
  • 因為每種策略(微信支付、支付寶支付)的內容都比較復雜。策略模式能將每種策略分離出來,方面後續維護管理

下面我們將使用Spring boot 運用策略模式,實現上面的需求

環境配置

  • JDK8
  • Spring boot 2.3.7.RELEASE
  • 整合瞭spring-boot-starter-web

實現目標

使用策略模式後,新加一種支付策略時,隻需要在策略枚舉中添加新加的策略信息,外加一個策略類即可,而不再需要添加新的if判斷。

準備策略接口和具體實現策略類

支付策略接口

/**
 * 支付策略
 */
public interface PayStrategy {

    /**
     * 支付(參數就沒具體寫瞭,可以定義成每個支付必須要有的參數)
     * @return
     */
     boolean pay();
}

微信支付策略類

/**
 * 第三方——微信支付(這裡註意我修改瞭Bean的默認命名)
 */
@Component("wechatPayStrategy")
public class WeChatPayStrategyImpl implements PayStrategy{

    /**
     * 支付
     * @return
     */
    @Override
    public boolean pay() {

        //進行微信的支付邏輯
        System.out.println("正在進行微信的支付邏輯");

        return true;
    }
}

支付寶支付策略類

/**
 * 支付寶第三方支付(這裡註意我修改瞭Bean的默認命名)
 */
@Component("alipayStrategy")
public class AliPayStrategyImpl implements PayStrategy {

    /**
     * 支付寶支付
     * @return
     */
    @Override
    public boolean pay() {

        //進行支付寶支付邏輯
        System.out.println("進行支付寶支付邏輯");
        return true;
    }
}

上述已將各自的策略的處理類進行瞭分離,接下來時使用支付策略工廠類和支付策略上下文將各自的策略類聯系起來

準備支付策略上下文Context和支付策略工廠類

支付策略工廠類

package com.example.springboot_strategy.strategy.factory;

import com.example.springboot_strategy.enums.PayStrategyEnum;
import com.example.springboot_strategy.strategy.PayStrategy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.swing.plaf.synth.SynthTextAreaUI;
import java.util.Map;

/**
 * 支付策略工廠類
 */
@Component
public class PayStrategyFactory {

    /**
     * 通過Spring容器的方式註入
     */
    @Resource
    private Map<String, PayStrategy> payStrategyMap;

    /**
     * 獲取對應支付策略類
     * @param payStrategyEnum 支付策略枚舉
     */
    public PayStrategy getPayStrategy(PayStrategyEnum payStrategyEnum){

        if(!payStrategyMap.containsKey(payStrategyEnum.getClassName())){
            System.out.println("沒有對應的支付策略,無法進行支付");
            return null;
        }

        return payStrategyMap.get(payStrategyEnum.getClassName());
    }
}

這裡工廠類的邏輯是利用瞭Spring容器的處理方式,如果有多種類同時實現瞭某個接口,那麼可以使用Map集合接收,Map對應的泛型,String是Bean名稱,PayStrategy是每個具體實現類,這樣我們就可以使用Bean類型去指定具體的策略類瞭,然後建立一個支付策略枚舉去管理這些Bean名稱。同時,也可以將Bean名稱與客戶端定義的類型進行關聯。

支付策略枚舉類

/**
 * 支付策略類型
 */
public enum PayStrategyEnum {
    WECHAT_PAY("wechat","wechatPayStrategy","微信支付"),
    ALIPAY("alipay","alipayStrategy","支付寶支付")
    ;

    /**
     * 支付策略code
     */
    private String code;

    /**
     * bean名稱
     */
    private String className;

    /**
     * 信息
     */
    private String info;

    PayStrategyEnum(String code,String className,String info){
        this.code=code;
        this.className=className;
        this.info=info;
    }


    public String getCode() {
        return code;
    }

    public String getClassName() {
        return className;
    }

    public String getInfo() {
        return info;
    }
}

上面枚舉類中code代表的是客戶端定義的類型(例如我從前端接收到的支付type,這個type可以是這個code),className顧名思義,指的是每種策略的bean名稱,info是代表每種策略的內容

支付策略上下文

/**
 * 支付策略上下文
 */
@Component
public class PayStrategyContext {
    
    @Autowired
    private PayStrategyFactory payStrategyFactory;

    /**
     * 支付執行
     * @param payDTO 支付參數
     * @return
     */
    public boolean payHandle(PayDTO payDTO){
       
        //將某屬性的值轉換成具體的枚舉。這裡是根據payDTO的type字段對應枚舉的code進行轉換
        Optional<PayStrategyEnum> payStrategyEnumOptional = Arrays.stream(PayStrategyEnum.class.getEnumConstants())
                .filter((e) -> e.getCode().equals(payDTO.getType())).findAny();

        if(!payStrategyEnumOptional.isPresent()){
            System.out.println("匹配不到具體支付策略");
            return false;
        }
        PayStrategyEnum payStrategyEnum = payStrategyEnumOptional.get();

        PayStrategy payStrategy = payStrategyFactory.getPayStrategy(payStrategyEnum);

        //進行payDto參數的處理.....

        boolean pay = payStrategy.pay();

        //支付後的記錄處理..


        return true;
        
    }
}

pageDto類

/**
 * 支付DTO
 */
public class PayDTO {

    /**
     * 支付類型
     */
    private String type;


    /**
     * 支付金額
     */
    private BigDecimal payMoney;
    
    /**
     * ...........
     */


    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public BigDecimal getPayMoney() {
        return payMoney;
    }

    public void setPayMoney(BigDecimal payMoney) {
        this.payMoney = payMoney;
    }

}

這個策略上下文,則是選擇策略的入口,這裡會進行參數的處理,將這裡我就將pageDTO類中的type字符串轉換成對應的枚舉類。
到這裡使用策略模式的編寫算是完成瞭,下面進行編寫客戶端的代碼

客戶端代碼

支付控制器

@RestController
@RequestMapping("pay")
public class PayController {

    @Autowired
    private PayStrategyContext payStrategyContext;

    @PostMapping
    public boolean pay(@RequestBody PayDTO payDTO){
    
        //這裡因為懶。。就沒有加上Service層瞭,直接在控制器處理
        return payStrategyContext.payHandle(payDTO);
    }
}

效果

新需求

後續新增一個銀聯的支付方式,我們隻需要添加銀聯的支付策略類和添加銀聯的支付枚舉即可實現

添加銀聯的支付策略類

/**
 * 銀聯支付(這裡註意我修改瞭Bean的默認命名)
 */
@Component("unionPayStrategy")
public class UnionPayStrategyImp implements PayStrategy {


    /**
     * 銀聯支付
     * @return
     */
    @Override
    public boolean pay() {

        //進行銀聯的支付

        System.out.println("進行銀聯的支付邏輯");
        return true;
    }

}
復制代碼

在枚舉類中添加銀聯的支付枚舉

/**
 * 支付策略類型
 */
public enum PayStrategyEnum {
    WECHAT_PAY("wechat","wechatPayStrategy","微信支付"),
    ALIPAY("alipay","alipayStrategy","支付寶支付"),
    UNION_PAY("unionpay","unionPayStrategy","銀聯支付")
    ;

    /**
     * 支付策略code
     */
    private String code;

    /**
     * bean名稱
     */
    private String className;

    /**
     * 信息
     */
    private String info;

    PayStrategyEnum(String code,String className,String info){
        this.code=code;
        this.className=className;
        this.info=info;
    }


    public String getCode() {
        return code;
    }

    public String getClassName() {
        return className;
    }

    public String getInfo() {
        return info;
    }


}

實現效果

以上是我使用Spring boot 運用策略模式實現的效果,如果有誤人子弟的地方,望在評論區指出。

到此這篇關於Spring boot 運用策略模式實現,避免多次使用if的文章就介紹到這瞭,更多相關Spring boot 策略模式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: