設計模式(一) 支付策略模式
阿新 • • 發佈:2019-07-16
使用場景
公司最近在做直播功能,底層原來有一套直播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