成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

再一次實戰策略模式,真是太好用了

開發 前端
之前做三方支付系統的時候經常用到策略模式,比如用戶會選擇不同的支付方式,不同的支付方式又有不同的實現方法或銀行接口調用。

[[384718]]

本文轉載自微信公眾號「程序新視界」,作者二師兄。轉載本文請聯系程序新視界公眾號。   

前言

之前做三方支付系統的時候經常用到策略模式,比如用戶會選擇不同的支付方式,不同的支付方式又有不同的實現方法或銀行接口調用。

現在做物聯網系統,基于MQTT協議(TCP層面的協議)來傳輸數據,根據不同的請求(不同的Topic)處理不同的業務邏輯,也同樣用到策略模式。

頓時感覺策略模式非常好用,而且結合Spring的實例化和注入功能,更加方便了。

今天就聊聊基于Spring(Boot)下策略模式的使用。

未使用策略模式時的處理

以物聯網為例大家可能不夠熟悉,下面就以支付場景為例。比如在支付的過程中我們可能會選擇微信支付、支付寶支付或銀卡支付。同時,銀行卡又分不同銀行,這里統一為銀行卡。

最簡單直接的代碼實現形式如下:

  1. public void pay(String payType){ 
  2.     if("alipay".equals(payType)){ 
  3.         System.out.println("支付寶"); 
  4.     }else if("wechatPay".equals(payType)){ 
  5.         System.out.println("微信支付"); 
  6.     } else if("bank".equals(payType)){ 
  7.         System.out.println("銀行卡支付"); 
  8.     } 

這樣對照設計模式,通常不符合兩個原則:單一職責原則和開閉原則。

我們會發現當前類(或方法)不處理了多個業務的功能,一旦任何一個支付方式的修改都可能會影響到其他的支付方式。同時,無法做到對擴展開放,對修改關閉。新增其他支付方式時同樣要修改ifelse判斷,影響到其他的業務邏輯。

而策略模式通常就是解決這種有很多ifelse處理邏輯,從而提高代碼的可維護性、可擴展性和可讀性。

策略模式的輪廓

在對上述代碼進行改造之前,先來了解一下策略模式的基本組成。

策略模式(Strategy),定義了一組算法,將每個算法都封裝起來,并且使它們之間可以互換。

策略模式通常由以下幾部分組成:

  • Strategy策略類,用于定義所有支持算法的公共接口;
  • ConcreteStrategy具體策略類,封裝了具體的算法或行為,繼承于Strategy。
  • Context上下文,用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用;
  • StrategyFactory策略工廠類,用于創建策略類的具體實現;通常此部分可省略,看具體情況。比如后續實例中通過Spring的依賴注入機制實現了策略類的實例化。

用類圖來表示(省略策略工廠類)如下圖:

image

 

基于Spring的策略模式實現

目前在實踐中通常都是基于Spring的特性來實現策略模式,這里就以此為例來進行講解。

策略類定義

上面已經提到,策略類用于定義功能的接口,對于支付場景則可命名為PaymentService或PaymentStrategy。

  1. public interface PaymentService { 
  2.  
  3.     /** 
  4.      * 支付 
  5.      */ 
  6.     PayResult pay(Order order); 

同時提供該策略類的不同實現類:AlipayService、WeChatPayService、BankPayService。

  1. @Service("alipay"
  2. public class AlipayService implements PaymentService { 
  3.     @Override 
  4.     public PayResult pay(Order order) { 
  5.         System.out.println("Alipay"); 
  6.         return null
  7.     } 
  1. @Service("wechatPay"
  2. public class WeChatPayService implements PaymentService { 
  3.     @Override 
  4.     public PayResult pay(Order order) { 
  5.         System.out.println("WeChatPay"); 
  6.         return null
  7.     } 
  1. @Service("bank"
  2. public class BankPayService implements PaymentService { 
  3.     @Override 
  4.     public PayResult pay(Order order) { 
  5.         System.out.println("BankPay"); 
  6.         return null
  7.     } 

具體實現的實例化,可以通過一個PaymentFactory來進行構建存儲,也可以直接利用@Autowired形式注入到Context的List或Map當中。

PaymentFactory的實現如下:

  1. public class PaymentFactory { 
  2.  
  3.     private static final Map<String, PaymentService> payStrategies = new HashMap<>(); 
  4.  
  5.     static { 
  6.         payStrategies.put("alipay", new AlipayService()); 
  7.         payStrategies.put("wechatPay", new WeChatPayService()); 
  8.         payStrategies.put("bank", new BankPayService()); 
  9.     } 
  10.  
  11.     public static PaymentService getPayment(String payType) { 
  12.         if (payType == null) { 
  13.             throw new IllegalArgumentException("pay type is empty."); 
  14.         } 
  15.         if (!payStrategies.containsKey(payType)) { 
  16.             throw new IllegalArgumentException("pay type not supported."); 
  17.         } 
  18.         return payStrategies.get(payType); 
  19.     } 

通過static靜態代碼塊來初始化對應的策略實現類,然后提供一個getPayment方法,根據支付類型來獲取對應的服務。當然,通過static初始化的代碼塊是單例的無狀態的,如果需要有狀態的類則getPayment方法,每次都需要new一個新的對象。

  1. public static PaymentService getPayment1(String payType) { 
  2.     if (payType == null) { 
  3.         throw new IllegalArgumentException("pay type is empty."); 
  4.     } 
  5.     if ("alipay".equals(payType)) { 
  6.         return new AlipayService(); 
  7.     } else if ("wechatPay".equals(payType)) { 
  8.         return new WeChatPayService(); 
  9.     } else if ("bank".equals(payType)) { 
  10.         return new BankPayService(); 
  11.     } 
  12.     throw new IllegalArgumentException("pay type not supported."); 

Context上下文

Context上下文角色,也叫Context封裝角色,起承上啟下的作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化。

上面通過工廠的形式創建策略類的實現類,當然也可以直接通過@Autowired注入到Context上下文中。

  1. @Component 
  2. public class PaymentStrategy { 
  3.  
  4.     @Autowired 
  5.     private final Map<String, PaymentService> payStrategies = new HashMap<>(); 
  6.  
  7.     public PaymentService getPayment(String payType) { 
  8.         if (payType == null) { 
  9.             throw new IllegalArgumentException("pay type is empty."); 
  10.         } 
  11.         if (!payStrategies.containsKey(payType)) { 
  12.             throw new IllegalArgumentException("pay type not supported."); 
  13.         } 
  14.         return payStrategies.get(payType); 
  15.     } 

上面通過@Autowired注解,將通過@Service實例化的PaymentService實現類,注入到map當中,其中key為實例化類的名稱,value為具體的實例化類。

上面的getPayment代碼與PaymentFactory中一致。當然,還可以在PaymentStrategy中封裝一個pay方法,這樣,客戶端直接注入PaymentStrategy類調用pay方法即可。

  1. public PayResult pay(String payType,Order order){ 
  2.     PaymentService paymentService = this.getPayment(payType); 
  3.     return paymentService.pay(order); 

改進方案

通過上面的代碼基本上已經實現了策略模式,此時當新增加一個支付通道時,已經不用修改PaymentStrategy相關的代碼,只用新增一個實現PaymentService接口的類即可。

但在接口定義這里,還是有優化空間的。比如,這里判斷是通過Bean的名稱來判斷的,但某些情況下判斷可能比較復雜或可能會同時執行多個Service。此時,就可以對PaymentService接口進行改進,新增一個檢驗是否支持該功能的判斷方法。

  1. public interface PaymentService { 
  2.  
  3.     boolean isSupport(Order order); 
  4.  
  5.     /** 
  6.      * 支付 
  7.      */ 
  8.     PayResult pay(Order order); 

由實現類來具體實現isSupport方法,判斷自己支持哪些功能。

同時,上下文類也可以進一步利用Java8提供的Steam特性進行處理:

  1. @Component 
  2. public class PaymentStrategy { 
  3.  
  4.     /** 
  5.      * 此處用@Autowired將所有實例注入為List。 
  6.      */ 
  7.     @Autowired 
  8.     private List<PaymentService> paymentServices; 
  9.  
  10.     public void pay(Order order) { 
  11.         PaymentService paymentService = paymentServices.stream() 
  12.                 .filter((service) -> service.isSupport(order)) 
  13.                 .findFirst() 
  14.                 .orElse(null); 
  15.  
  16.         if (paymentService != null) { 
  17.             paymentService.pay(order); 
  18.         } else { 
  19.             throw new IllegalArgumentException("pay type not supported."); 
  20.         } 
  21.     } 

通過進一步改造,程序變得更加靈活了。

小結

通過上面的代碼實現,可以看出接口類只負責業務策略的定義,策略的具體實現可以單獨放在實現類中也可以利用Spring的特性進行管理,Context上下文類負責業務邏輯的編排。

通過策略模式(或變種)的應用,實現了面向接口而非實現編程,滿足了職責單一、開閉原則,從而達到了功能上的高內聚低耦合、提高了可維護性、擴展性以及代碼的可讀性。

 

最后,對于設計模式,只有在實踐中不斷的使用采用更加印象深刻。同時,在實現的過程中我們也并不一定非要拘泥于設計模式本身,也可以結合所使用的框架進行變種處理。

 

責任編輯:武曉燕 來源: 程序新視界
相關推薦

2016-03-17 13:50:17

融合通信華為

2015-08-07 13:36:49

南京軟博會

2012-03-09 15:55:05

新版

2017-02-28 11:13:36

華為

2015-05-28 09:58:00

手機電池續航內存

2013-08-23 10:12:02

蘋果iPhone 5S

2015-10-14 13:02:37

ios9越獄

2014-09-24 13:08:35

微信企業號

2021-11-01 22:24:08

電腦配置設置

2012-08-10 09:29:36

imo即時通訊

2020-09-23 06:52:49

代碼方法模式

2022-04-26 14:14:32

數字人民幣支付數字化

2023-03-16 18:30:55

GPT-4ChatGPT

2022-11-07 11:42:36

人工智能機器人無人駕駛

2024-12-13 16:01:35

2021-05-26 17:33:47

AI 數據人工智能

2021-05-10 19:17:54

GoInt128類型

2021-04-22 09:56:32

MYSQL開發數據庫

2022-08-01 07:02:06

SpringEasyExcel場景

2018-12-24 09:42:53

人工智能機器學習技術
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91国产在线视频在线 | 欧美日韩久久精品 | 一区二区三区亚洲精品国 | 免费观看黄色一级片 | 日本免费在线观看视频 | 亚洲第一天堂 | 91欧美| 亚洲精品一区在线观看 | 在线视频91 | 色婷婷亚洲 | 伊人无码高清 | 91免费电影 | 日本高清中文字幕 | 偷拍自拍网 | 亚洲精品丝袜日韩 | 国产免费一二三区 | 国产成人精品在线播放 | 欧美电影在线观看网站 | 国产成人亚洲精品自产在线 | 国产 亚洲 网红 主播 | 亚洲aⅴ | av免费在线播放 | 日韩二区 | 国内精品视频一区二区三区 | 久久99视频 | 国产午夜在线观看 | 日本欧美大片 | 亚洲人成人一区二区在线观看 | 久草精品视频 | 欧美在线成人影院 | 日批免费看 | 在线播放国产一区二区三区 | 91亚洲一区 | 国产一级免费视频 | 成人三区四区 | 日韩综合在线播放 | av日韩一区 | 永久免费av| 国产综合在线视频 | 精品久久香蕉国产线看观看亚洲 | 亚洲专区在线 |