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

換一種角度:從架構(gòu)層面來看設(shè)計模式

開發(fā) 架構(gòu) 新聞
本文嘗試從架構(gòu)層面來聊一聊設(shè)計模式。通過將使用設(shè)計模式的代碼和不使用設(shè)計模式的代碼分別放到架構(gòu)中,來看看設(shè)計模式對架構(gòu)所產(chǎn)生的影響。

 大部分講解設(shè)計模式的書或者文章,都是從代碼層面來講解設(shè)計模式,看的時候都懂,但是到真正用的時候,還是理不清、想不明。

本文嘗試從架構(gòu)層面來聊一聊設(shè)計模式。通過將使用設(shè)計模式的代碼和不使用設(shè)計模式的代碼分別放到架構(gòu)中,來看看設(shè)計模式對架構(gòu)所產(chǎn)生的影響。

一般模式講解套路

一般講解設(shè)計模式的套路是:

  • 說明模式的意圖
  • 說明模式的適用場景
  • 給出模式的類結(jié)構(gòu)
  • 給出對應(yīng)的代碼示例

以策略模式為例:

意圖:定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換。本模式使得算法可獨立于使用它的客戶而變化。

適用性

  • 許多相關(guān)的類僅僅是行為有異?!覆呗浴固峁┝艘环N用多個行為中的一個行為來配置一個類的方法。
  • 需要使用一個算法的不同變體。例如,你可能會定義一些反映不同的空間/時間權(quán)衡的算法。當(dāng)這些變體實現(xiàn)為一個算法的類層次時,可以使用策略模式。
  • 算法使用客戶不應(yīng)該知道的數(shù)據(jù)??墒褂貌呗阅J揭员苊獗┞稄?fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)。
  • 一個類定義了多種行為, 并且這些行為在這個類的操作中以多個條件語句的形式出現(xiàn)。將相關(guān)的條件分支移入它們各自的Strategy類中以代替這些條件語句。

類結(jié)構(gòu)

從架構(gòu)層面看設(shè)計模式

示例代碼

  1. public class Context { 
  2.  
  3.  //持有一個具體策略的對象 
  4.  private Strategy strategy; 
  5.  
  6.  /** 
  7.  * 構(gòu)造函數(shù),傳入一個具體策略對象 
  8.  * @param strategy 具體策略對象 
  9.  */ 
  10.  public Context(Strategy strategy){ 
  11.  this.strategy = strategy; 
  12.  } 
  13.   
  14.  /** 
  15.  * 策略方法 
  16.  */ 
  17.  public void invoke(){ 
  18.  strategy.doInvoke(); 
  19.  } 
  20.  
  21. public interface Strategy { 
  22.  
  23.  /** 
  24.  * 策略方法 
  25.  */ 
  26.  public void doInvoke(); 
  27.  
  28. public class StrategyA implements Strategy { 
  29.  
  30.  @Override 
  31.  public void doInvoke() { 
  32.  System.out.println("InvokeA"); 
  33.  } 
  34.  
  35. public class StrategyB implements Strategy { 
  36.  @Override 
  37.  public void doInvoke() { 
  38.  System.out.println("InvokeB"); 
  39.  } 

從上面的講解,你能理解策略模式嗎?你是否有如下的一些疑問?

  • 使用策略模式和我直接寫if-else具體的優(yōu)勢在哪里?
  • if-else不是挺簡單的,為什么要多寫這么多的類?
  • 如何將Strategy給設(shè)置到Context中?
  • 我該如何判斷將哪個實現(xiàn)設(shè)置給Context?還是ifelse?!那拆成這么多的類不是脫褲子放屁嗎?

將模式放入架構(gòu)中

產(chǎn)生這些疑問的原因,是我們在孤立的看設(shè)計模式,而沒有把設(shè)計模式放到實際的場景中。

當(dāng)我們將其放到實際項目中時,我們實際是需要一個客戶端來組裝和調(diào)用這個設(shè)計模式的,如下圖所示:

從架構(gòu)層面看設(shè)計模式
 
  1. public class Client { 
  2.   
  3.  public static void main(String[] args) { 
  4.  Strategy strategy; 
  5.  if("A".equals(args[0])) { 
  6.  strategy = new StrategyA(); 
  7.  } else { 
  8.  strategy = new StrategyB(); 
  9.  } 
  10.  Context context = new Context(strategy); 
  11.  context.invoke(); 
  12.  }  

作為比較,這里也給出直接使用ifelse時的結(jié)構(gòu)和代碼:

從架構(gòu)層面看設(shè)計模式
 
  1. public class Client { 
  2.  public static void main(String[] args) { 
  3.  Context context = new Context(args[0]); 
  4.  context.invoke(); 
  5.  } 
  6.  
  7. public class Context { 
  8.  public void invoke(String type) { 
  9.  if("A".equals(type)) { 
  10.  System.out.println("InvokeA"); 
  11.  } else if("B".equals(type)) { 
  12.  System.out.println("InvokeB"); 
  13.  } 
  14.  } 

乍看之下,使用ifelse更加的簡單明了,不過別急,下面我們來對比一下兩種實現(xiàn)方式的區(qū)別,來具體看看設(shè)計模式所帶來的優(yōu)勢。

邊界不同

首先,使用策略模式使得架構(gòu)的邊界與使用ifelse編碼方式的架構(gòu)的邊界不同。策略模式將代碼分成了三部分,這里稱為:

  • 調(diào)用層:將下層的業(yè)務(wù)邏輯組裝起來,形成完整的可執(zhí)行流程
  • 邏輯層:具體的業(yè)務(wù)邏輯流程
  • 實現(xiàn)層:實現(xiàn)業(yè)務(wù)邏輯中可替換邏輯的具體實現(xiàn)
從架構(gòu)層面看設(shè)計模式

而ifelse將代碼分成了兩部分:

  • 調(diào)用層:將下層的業(yè)務(wù)邏輯組裝起來,形成完整的可執(zhí)行流程
  • 邏輯層:具體的業(yè)務(wù)邏輯流程及具體邏輯
從架構(gòu)層面看設(shè)計模式

解耦

在ifelse實現(xiàn)中,「邏輯流程」和「邏輯實現(xiàn)」是硬編碼在一起的,明顯的緊耦合。而策略模式將「邏輯流程」和「邏輯實現(xiàn)」拆分開,對其進行了解耦。

解耦后,「邏輯流程」和「邏輯實現(xiàn)」就可以獨立的進化,而不會相互影響。

獨立進化

假設(shè)現(xiàn)在要調(diào)整業(yè)務(wù)流程。對于策略模式來說,需要修改的是「邏輯層」;而對于ifelse來說,需要修改的也是「邏輯層」。

假設(shè)現(xiàn)在要新增一個策略。對于策略模式來說,需要修改的是「實現(xiàn)層」;而對于ifelse來說,需要修改的還是「邏輯層」。

在軟件開發(fā)中,有一個原則叫單一職責(zé)原則,它不僅僅是針對類或方法的,它也適用于包、模塊甚至子系統(tǒng)。

對應(yīng)到這里,你會發(fā)現(xiàn),ifelse的實現(xiàn)方式違背了單一職責(zé)原則。使用ifelse實現(xiàn),使得邏輯層的職責(zé)不單一了。當(dāng)業(yè)務(wù)流程需要調(diào)整時,需要調(diào)整邏輯層的代碼;當(dāng)具體的業(yè)務(wù)邏輯實現(xiàn)需要調(diào)整時,也需要調(diào)整邏輯層。

而策略模式將業(yè)務(wù)流程和具體的業(yè)務(wù)邏輯拆分到了不同的層內(nèi),使得每一層的職責(zé)相對的單一,也就可以獨立的進化。

對象聚集

我們重新來觀察一下策略模式的架構(gòu)圖,再對照上面的調(diào)用代碼,你有沒有發(fā)現(xiàn)缺少了點什么?

在Client中,我們要根據(jù)參數(shù)判定來實例化了StategyA或StategyB對象。也就是說,「調(diào)用層」使用了「實現(xiàn)層」的代碼,實際調(diào)用邏輯應(yīng)該是這樣的:

從架構(gòu)層面看設(shè)計模式

可以看到,Client與StategyA和StategyB是強依賴的。這會導(dǎo)致兩個問題:

  • 對象分散:如果StategyA或StategyB的實例化方法需要調(diào)整,所有實例化代碼都需要進行調(diào)整?;蛘呷绻略隽薙tategyC,那么所有將Stategy設(shè)置到Context的相關(guān)代碼都需要調(diào)整。
  • 穩(wěn)定層依賴不穩(wěn)定層:一般情況下,「實現(xiàn)層」的變動頻率較高;而對于「調(diào)用層」來說,調(diào)用流程確定后,基本就不會變化了。讓一個基本不變的層去強依賴一個頻繁變化的層,顯然是有問題的。

我們先來解決「對象分散」的問題,下一節(jié)來解決「穩(wěn)定層依賴不穩(wěn)定層」的問題!

對于「對象分散」的問題來說,創(chuàng)建型的設(shè)計模式基本能解決這個問題,對應(yīng)到這里,可以直接使用工廠方法!

從架構(gòu)層面看設(shè)計模式

使用了工廠方法后,構(gòu)建代碼被限制在了工廠方法內(nèi)部,當(dāng)策略對象的構(gòu)造邏輯調(diào)整時,我們只需要調(diào)整對應(yīng)的工廠方法就可以了。

依賴倒置

現(xiàn)在「調(diào)用層」只和「實現(xiàn)層」的StategyFactoryImpl有直接的關(guān)系,解決了「對象分散」的問題。但是即使只依賴一個類,調(diào)用層依然和實現(xiàn)層是強依賴關(guān)系。

該如何解決這個問題呢?我們需要依賴倒置。一般方法是使用接口,例如這里的「邏輯層」和「實現(xiàn)層」就是通過接口來實現(xiàn)了依賴倒置:「邏輯層」并不強依賴于「實現(xiàn)層」的任何一個類。箭頭方向都是從「實現(xiàn)層」指向「邏輯層」的,所以稱為依賴倒置

從架構(gòu)層面看設(shè)計模式

但是對于「調(diào)用層」來說,此方法并不適用,因為它需要實例化具體的對象。那我們該如何處理呢?

相信你已經(jīng)想到了,就是我們一直在用的IOC!通過注入的方式,使得依賴倒置!我們可以直接替換掉工廠方法。

從架構(gòu)層面看設(shè)計模式

可以看到,通過依賴注入,使得「調(diào)用層」和「實現(xiàn)層」都依賴于「邏輯層」。由于「邏輯層」也是相對較穩(wěn)定的,所以「調(diào)用層」也就不會頻繁的變化,現(xiàn)在需要變化的只有「實現(xiàn)層」了。

邏輯顯化

最后一個區(qū)別就是設(shè)計模式使得邏輯顯化。什么意思呢?

當(dāng)你使用ifelse的時候,實際上你需要深入到具體的ifelse代碼,你才能知道它的具體邏輯是什么。

對于使用設(shè)計模式的代碼來說,我們回過頭來看上面的架構(gòu)圖,從這張圖你就能看出來對應(yīng)的邏輯了:

  • 由StrategyFactory實例化所有Strategy的實現(xiàn)
  • Client通過StrategyFactory獲取Strategy實例,并將其設(shè)置到Context中
  • 由Context委托給具體的Strategy來執(zhí)行具體的邏輯

至于具體的Strategy邏輯是什么樣子的,你可以通過類名或方法名來將其顯化出來!

總結(jié)

本文通過將使用設(shè)計模式的代碼和不使用設(shè)計模式的代碼分別放到架構(gòu)中,對比設(shè)計模式對架構(gòu)所產(chǎn)生的影響:

  • 劃分邊界
  • 解耦
  • 獨立進化
  • 對象聚集
  • 依賴倒置
  • 邏輯顯化
責(zé)任編輯:張燕妮 來源: 今日頭條
相關(guān)推薦

2021-08-06 16:57:39

存儲Redis數(shù)據(jù)類型

2019-10-28 11:30:43

架構(gòu)數(shù)據(jù)結(jié)構(gòu)布隆過濾器

2013-08-12 09:31:39

Windows操作系統(tǒng)

2017-07-05 14:09:04

系統(tǒng)設(shè)計與架構(gòu)java云計算

2022-09-27 08:04:37

Adapter?設(shè)計模式

2022-03-01 09:58:10

高并發(fā)架構(gòu)開發(fā)

2013-09-04 12:38:56

架構(gòu)設(shè)計架構(gòu)設(shè)計構(gòu)思

2012-01-17 11:02:39

2018-07-18 08:59:32

Redis存儲模式

2019-01-02 08:04:29

GAN損失函數(shù)神經(jīng)網(wǎng)絡(luò)

2017-03-21 17:04:05

Android客戶端架構(gòu)設(shè)計

2012-12-07 09:30:24

2020-10-19 13:05:32

架構(gòu)模式

2011-03-01 09:43:13

MapReduce架構(gòu)

2020-05-14 14:48:15

架構(gòu)模式單庫

2024-09-27 08:00:00

2012-12-25 10:48:35

IBMdW

2019-04-28 16:10:50

設(shè)計Redux前端

2023-09-17 23:16:46

緩存數(shù)據(jù)庫

2009-12-11 10:30:31

點贊
收藏

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