自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

再一次實戰(zhàn)策略模式,真是太好用了

開發(fā) 前端
之前做三方支付系統(tǒng)的時候經(jīng)常用到策略模式,比如用戶會選擇不同的支付方式,不同的支付方式又有不同的實現(xiàn)方法或銀行接口調(diào)用。

[[384718]]

本文轉(zhuǎn)載自微信公眾號「程序新視界」,作者二師兄。轉(zhuǎn)載本文請聯(lián)系程序新視界公眾號。   

前言

之前做三方支付系統(tǒng)的時候經(jīng)常用到策略模式,比如用戶會選擇不同的支付方式,不同的支付方式又有不同的實現(xiàn)方法或銀行接口調(diào)用。

現(xiàn)在做物聯(lián)網(wǎng)系統(tǒng),基于MQTT協(xié)議(TCP層面的協(xié)議)來傳輸數(shù)據(jù),根據(jù)不同的請求(不同的Topic)處理不同的業(yè)務邏輯,也同樣用到策略模式。

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

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

未使用策略模式時的處理

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

最簡單直接的代碼實現(xiàn)形式如下:

  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.     } 

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

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

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

策略模式的輪廓

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

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

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

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

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

image

 

基于Spring的策略模式實現(xiàn)

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

策略類定義

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

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

同時提供該策略類的不同實現(xiàn)類: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.     } 

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

PaymentFactory的實現(xiàn)如下:

  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靜態(tài)代碼塊來初始化對應的策略實現(xiàn)類,然后提供一個getPayment方法,根據(jù)支付類型來獲取對應的服務。當然,通過static初始化的代碼塊是單例的無狀態(tài)的,如果需要有狀態(tài)的類則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封裝角色,起承上啟下的作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化。

上面通過工廠的形式創(chuàng)建策略類的實現(xiàn)類,當然也可以直接通過@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實現(xiàn)類,注入到map當中,其中key為實例化類的名稱,value為具體的實例化類。

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

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

改進方案

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

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

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

由實現(xiàn)類來具體實現(xiàn)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.     } 

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

小結(jié)

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

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

 

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

 

責任編輯:武曉燕 來源: 程序新視界
相關(guān)推薦

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

手機電池續(xù)航內(nèi)存

2013-08-23 10:12:02

蘋果iPhone 5S

2015-10-14 13:02:37

ios9越獄

2014-09-24 13:08:35

微信企業(yè)號

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

數(shù)字人民幣支付數(shù)字化

2022-11-07 11:42:36

人工智能機器人無人駕駛

2023-03-16 18:30:55

GPT-4ChatGPT

2021-05-26 17:33:47

AI 數(shù)據(jù)人工智能

2021-05-10 19:17:54

GoInt128類型

2024-12-13 16:01:35

2022-05-31 09:42:49

工具編輯器

2024-05-11 09:38:05

React編譯器React 19

2021-04-22 09:56:32

MYSQL開發(fā)數(shù)據(jù)庫
點贊
收藏

51CTO技術(shù)棧公眾號