1. 程式人生 > >設計模式(一) 支付策略模式

設計模式(一) 支付策略模式

 

使用場景

公司最近在做直播功能,底層原來有一套直播API,現在新增一套網宿直播API。
考慮以後的擴充套件性,需要將兩套API進行統一管理。現在以網上的支付方式演示我對策略模式的理解。

支付方式

我們知道網上有很多支付方式。支付寶、微信、銀行卡、花唄...
我們以三種支付方式進行演示。

 

策略模式的組成有三部分

 

環境類(Context):用一個ConcreteStrategy物件來配置。維護一個對Strategy物件的引用。

可定義一個介面來讓Strategy訪問它的資料,在上一個例子中相當於Staff。

抽象策略類(Strategy):定義所有支援的演算法的公共介面。 Context使用這個介面來呼叫某ConcreteStrategy定義的演算法,

在上一個例子中相當於GrantReward。
具體策略類(ConcreteStrategy):以Strategy介面實現某具體演算法,在上一個例子中相當於GrantSuger,GrantMoonCake,GrantNone。

 

支付方式的組成也有三部分

 

支付策略介面(PayStrategy):定義支付方式
具體支付方式(AliPayStrategy、WxPayStrategy、CardPayStrategy):具體的支付演算法
支付策略上下文(PayStrategyContent):管理所有支付方式的引用,並根據使用者選擇引用對應的支付方式。

 

程式碼實現

 

支付策略介面(PayStrategy)

 1 /**
 2  * 支付策略介面
 3  * @author JinXing
 4  * @date 2019/7/12 13:58
 5  */
 6 public interface PayStrategy {
 7 
 8 
 9 
10     /**
11      *
12      * 選擇支付方式
13      * 支付寶
14      * 微信
15      * 銀行卡
16      * @return RemoteResult
17      */
18     RemoteResult<String> toPayHtml();
19 
20 
21 }

 

 

具體支付方式(AliPayStrategy)

 1 /**
 2  * 阿里pay
 3  * @author JinXing
 4  * @date 2019/7/12 14:36
 5  */
 6 @Service
 7 public class AliPayStrategy implements PayStrategy {
 8 
 9     @Override
10     public RemoteResult<String> toPayHtml() {
11 
12         System.out.println("現在採用的支付方式為:支付寶支付......");
13 
14         return null;
15     }
16 }

 

具體支付方式(WxPayStrategy)

 1 /**
 2  * 微信支付
 3  * @author JinXing
 4  * @date 2019/7/12 14:36
 5  */
 6 
 7 @Service
 8 public class WxPayStrategy implements PayStrategy {
 9 
10     @Override
11     public RemoteResult<String> toPayHtml() {
12 
13         System.out.println("現在採用的支付方式為:微信支付......");
14 
15         return null;
16     }
17 }

 

具體支付方式(CardPayStrategy)

 1 /**
 2  * 銀行卡支付
 3  * @author JinXing
 4  * @date 2019/7/12 14:36
 5  */
 6 
 7 @Service
 8 public class CardPayStrategy implements PayStrategy {
 9 
10     @Override
11     public RemoteResult<String> toPayHtml() {
12 
13         System.out.println("現在採用的支付方式為:銀行卡支付......");
14 
15         return null;
16     }
17 }

 

支付策略上下文(PayStrategyContent)

/**
 * 支付策略上下文
 * @author JinXing
 * @date 2019/7/12 14:39
 */

@Component
public class PayStrategyContent {


    /** 策略例項集合 */
    private ConcurrentHashMap<String, PayStrategy> strategyMap = new ConcurrentHashMap<>(20);

    /**
     * 注入策略例項
     * 如果使用的是構造器注入,可能會有多個引數注入進來。
     *
     * 如果使用的是field反射注入
     *
     * 如果使用的是setter方法注入,那麼你將不能將屬性設定為final。
     *
     * @param strategyMap
     *         注意注入型別要是Map基礎型別
     */
    @Autowired
    public PayStrategyContent(Map<String, PayStrategy> strategyMap) {
        //清空集合資料
        this.strategyMap.clear();

        if (!CollectionUtils.isEmpty(strategyMap)) {
            strategyMap.forEach((beanName, payStrategy) -> {
                if (StringUtils.isEmpty(beanName) || payStrategy == null) {
                    return;
                }
                this.strategyMap.put(beanName.toLowerCase(), payStrategy);
            });
        }
    }


    /**
     * 選擇支付方式
     * 支付寶、微信、銀行卡
     *
     * @param paymentEnums
     *
     * @return RemoteResult
     */
    RemoteResult<String> toPayHtml(PaymentEnums paymentEnums) {

        if (CollectionUtils.isEmpty(strategyMap)) {
            return new RemoteResult<String>().error("策略例項集合初始化失敗,請檢查是否正確注入!");
        }

        return this.strategyMap.get(paymentEnums.getBeanName()).toPayHtml();
    }

}

 

支付方式列舉(PaymentEnums)

**
 * 支付方式列舉物件
 * code -> 支付方式別名
 * beanName -> 例項的名稱
 *
 * @author JinXing
 * @date 2019/7/12 14:40
 */
public enum PaymentEnums {

    /** 支付方式 */
    ALI_PAY("ali_pay", AliPayStrategy.class.getSimpleName()),
    WX_PAY("WX_PAY", WxPayStrategy.class.getSimpleName()),
    CARD_PAY("card_pay", CardPayStrategy.class.getSimpleName()),

    ;

    /** 列舉定義+描述 */
    private String code;
    private String beanName;

    PaymentEnums(String code, String beanName) {
        this.code = code;
        this.beanName = StringUtils.isNotEmpty(beanName)?beanName.toLowerCase():null;
    }


    /** 根據code獲取對應的列舉物件 */
    public static PaymentEnums getEnum(String code) {
        PaymentEnums[] values = PaymentEnums.values();
        if (null != code && values.length > 0) {
            for (PaymentEnums value : values) {
                if (value.code.equals(code)) {
                    return value;
                }
            }
        }
        return null;
    }

    /** 該code在列舉列表code屬性是否存在 */
    public static boolean containsCode(String code) {
        PaymentEnums anEnum = getEnum(code);
        return anEnum != null;
    }

    /** 判斷code與列舉中的code是否相同 */
    public static boolean equals(String code, PaymentEnums calendarSourceEnum) {
        return calendarSourceEnum.code.equals(code);
    }


    public String getCode() {
        return code;
    }

    public String getBeanName() {
        return beanName;
    }
}

 

結果集包裝類(RemoteResult)

 1 /**
 2  * <pre>
 3  * 遠端介面值物件,此物件使用說明
 4  * 使用時,判斷isSuccess返回值,true表示業務成功、false表示介面呼叫失敗
 5  * errorCode,用於判斷失敗原因(非系統錯誤),系統預設錯誤碼,用負數表示:-1表示引數不合法,使用者自定義錯誤碼使用正數表示,0表示無錯誤
 6  * </pre>
 7  *
 8  * @author jx
 9  * @param <T>
10  */
11 
12 
13 public class RemoteResult<T> implements Serializable {
14 
15     private static final long serialVersionUID = 1L;
16     /** 介面呼叫是否成功(業務),系統錯誤、業務失敗都將返回false */
17     private boolean isSuccess = true;
18     /** 自定義錯誤資訊,發生可處理錯誤時,返回自定義資訊 */
19     private String errorMsg = "ok";
20     /** 介面返回結果(Void表示無返回值) */
21     private T result;
22     /** 異常堆疊資訊,需要提供除錯功能時,將異常加入此堆疊中,便於協調呼叫方除錯,僅作除錯用 */
23     private Exception exceptionStack;
24 
25     public RemoteResult() {
26     }
27 
28     public RemoteResult<T> error(String errorMsg) {
29         this.errorMsg = errorMsg;
30         this.isSuccess = false;
31         return this;
32     }
33 
34     public static long getSerialVersionUID() {
35         return serialVersionUID;
36     }
37 
38     public boolean isSuccess() {
39         return isSuccess;
40     }
41 
42     public void setSuccess(boolean success) {
43         isSuccess = success;
44     }
45 
46     public String getErrorMsg() {
47         return errorMsg;
48     }
49 
50     public void setErrorMsg(String errorMsg) {
51         this.errorMsg = errorMsg;
52     }
53 
54     public T getResult() {
55         return result;
56     }
57 
58     public void setResult(T result) {
59         this.result = result;
60     }
61 
62     public Exception getExceptionStack() {
63         return exceptionStack;
64     }
65 
66     public void setExceptionStack(Exception exceptionStack) {
67         this.exceptionStack = exceptionStack;
68     }
69 
70 }

 

&n