我們在購買網易雲音樂會員的時候,支付頁有兩個選項,分别是支付寶支付和微信支付,這個背景結算進行開發的時候,如果要提高程式的可維護性,那麼大機率會使用标題所提到的政策模式。
1.模式定義
這裡就直接給出GoF的官方定義吧,後續我們圍繞這個定義展開:
Define a family of algorithms, encapsulate each one, and make them interchangeable.
定義一個算法家族,分别封裝起來,使得它們之間可以互相變換。
可以看到,這個定義就非常吻合我們的這個支付場景了,網易雲可以内容實作了支付寶支付政策,微信支付政策,使用者根據情況選擇其中的一種支付方式,便是選擇其中的一種支付政策。
2.模式結構
這裡是正常的政策模式的模式結構圖
https://refactoringguru.cn/design-patterns/strategy
實際開發我們會考慮各種優化,以及使用各種開發架構如Spring,會和結構圖中有所差別:
- 設定政策的方式通常是傳入政策枚舉,而不是new一個政策并傳入context中,基于Spring進行開發的企業級項目,通常不會有手動new一個服務的操作,而是注冊為一個個的Spring的bean。
- 每個政策都應該單例化,而Spring預設就是單例模式,完美結合。
3.模式實作
本着了解的模式為先的原則,是以代碼結構力求簡單明了。同時貼近實際生産,如使用了Spring架構等。
3.1.定義支付枚舉
後續新增支付方式,記得這裡維護下
package com.example.designpattern.strategy.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 支付政策
*
* @author hongcunlin
*/
@Getter
@AllArgsConstructor
public enum PayEnums {
/**
* 支付寶支付
*/
ALI(1, "支付寶支付"),
/**
* 微信支付
*/
WE_CHAT(2, "微信支付");
/**
* 支付類型碼
*/
private final Integer code;
/**
* 支付類型名稱
*/
private final String name;
}
3.2.定義支付政策
package com.example.designpattern.strategy.paystrategy;
/**
* 支付政策
*
* @author hongcunlin
*/
public interface PayStrategy {
/**
* 支付
*/
void pay();
}
3.3.實作支付寶支付、微信支付政策
package com.example.designpattern.strategy.paystrategy.impl;
import com.example.designpattern.strategy.paystrategy.PayStrategy;
import org.springframework.stereotype.Service;
/**
* 支付寶支付
*
* @author hongcunlin
*/
@Service
public class AliPayStrategy implements PayStrategy {
@Override
public void pay() {
System.out.println("支付寶支付");
}
}
package com.example.designpattern.strategy.paystrategy.impl;
import com.example.designpattern.strategy.paystrategy.PayStrategy;
import org.springframework.stereotype.Service;
/**
* 微信支付
*
* @author hongcunlin
*/
@Service
public class WeChatPayStrategy implements PayStrategy {
@Override
public void pay() {
System.out.println("微信支付");
}
}
另外實際開發中,通常會有一個預設的實作用于兜底。
package com.example.designpattern.strategy.paystrategy.impl;
import com.example.designpattern.strategy.paystrategy.PayStrategy;
import org.springframework.stereotype.Service;
/**
* 預設支付
*
* @author hongcunlin
*/
@Service
public class DefaultPayStrategy implements PayStrategy {
@Override
public void pay() {
System.out.println("支付失敗");
}
}
3.4.定義支付上下文
這類注入了各大政策實作
package com.example.designpattern.strategy.context;
import com.example.designpattern.strategy.enums.PayEnums;
import com.example.designpattern.strategy.paystrategy.PayStrategy;
import com.example.designpattern.strategy.paystrategy.impl.AliPayStrategy;
import com.example.designpattern.strategy.paystrategy.impl.DefaultPayStrategy;
import com.example.designpattern.strategy.paystrategy.impl.WeChatPayStrategy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 支付上下文
*
* @author hongcunlin
*/
@Component
public class PayContext {
/**
* 支付政策
*/
private PayStrategy payStrategy;
/**
* 預設支付
*/
@Resource
private DefaultPayStrategy defaultPayStrategy;
/**
* 支付寶支付
*/
@Resource
private AliPayStrategy aliPayStrategy;
/**
* 微信支付
*/
@Resource
private WeChatPayStrategy weChatPayStrategy;
/**
* 設定支付政策
*
* @param code 支付政策碼
*/
public void setPayStrategy(Integer code) {
if (PayEnums.ALI.getCode().equals(code)) {
payStrategy = aliPayStrategy;
} else if (PayEnums.WE_CHAT.getCode().equals(code)) {
payStrategy = weChatPayStrategy;
} else {
payStrategy = defaultPayStrategy;
}
}
/**
* 執行政策
*/
public void execute() {
if (null == payStrategy) {
throw new RuntimeException("未設定支付方式");
}
payStrategy.pay();
}
}
3.5.測試
我們注入支付上下文PayContext,通過枚舉指定支付的方式,執行PayContext的execute方法完成支付。
package com.example.designpattern.strategy;
import com.example.designpattern.strategy.context.PayContext;
import com.example.designpattern.strategy.enums.PayEnums;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
public class DesignPatternTest {
/**
* 支付上下文
*/
@Resource
private PayContext payContext;
/**
* 測試
*/
@Test
public void test() {
payContext.setPayStrategy(PayEnums.ALI.getCode());
payContext.execute();
}
}
這是運作結果,可以看到,是符合我們的預期的
4.模式優點
最後來簡單聊聊使用了政策模式後的有點,主要展現在如果後面網易雲音樂會員支援方式,新增了京東支付、抖音支付等支付方式,我們可以通過新增相應的京東支付政策、抖音支付政策即可,原有的主流程無需改變,即:
每新增一個政策,隻需要新增政策的實作即可,無需改動原有的流程。
後續有空,我們接着依據現實生活,聊聊設計模式中的其他設計模式。