1. 程式人生 > >Java中,狀態模式和策略模式的區別

Java中,狀態模式和策略模式的區別

Java開發者,要想恰當的使用狀態模式和策略模式,必須清楚的理解它們之間的區別。雖然狀態模式和策略模式擁有相似的結構,雖然它們都基於SOLID設計原則中的O(開閉原則),但是,它們的意圖是完全不同的。

策略模式通過封裝一組相關演算法,為Client提供執行時的靈活性。Client可以在執行時,選擇任一演算法,而不改變使用演算法的Context。一些流行的策略模式的例子是寫那些使用演算法的程式碼,例如加密演算法、壓縮演算法、排序演算法。另一方面,狀態模式允許物件,在不同的狀態擁有不同的行為。因為現實世界中的物件通常都是有狀態的,所以它們在不同狀態,行為也不一樣。例如,VM(自動售貨機)只在hasCoin狀態才給你吐商品;你不投幣,它是不會吐的。現在你可以清楚的看出它們的不同之處了:它們的意圖是不同的。狀態模式幫助物件管理狀態,而策略模式允許Client選擇不同的行為。


另一個不那麼容易能看出來的區別是:是誰促使了行為的改變。策略模式中,是Client提供了不同的策略給Context;狀態模式中,狀態轉移由Context或State自己管理。另外,如果你在State中管理狀態轉移,那麼它必須持有Context的引用。例如,在VM的例子中,State物件需要呼叫VM的setState()方法去改變它的狀態。另一方面,Strategy從不持有Context的引用,是Client把所選擇的Strategy傳遞給Context。由於狀態模式和策略模式的區別,是流行的Java設計原則類面試題之一,我們將會在本文探討在Java中,狀態模式和策略模式的異同,這可以加深你對它們的理解。

相似之處

如果你看看狀態模式和策略模式的UML圖,就會發現它們的結構非常相似。使用State物件改變自己行為的物件被稱為Context物件;相似的,使用Strategy物件改變自己行為的物件叫Context物件。記住,Client和Context打交道。在狀態模式中,Context把方法呼叫委託給當前的狀態物件,而在策略模式中,Context使用的Strategy物件,是被當做引數傳遞過來的,或在Context物件被建立時就被提供的。

狀態模式UML類圖

這是專為經典的VM問題而設計的狀態模式UML類圖。你可以看出,VM的狀態是個介面,它有表示不同狀態的具體實現。每一個狀態都持有Context的引用,用它來管理由Context觸發的行為導致的狀態轉移。

策略模式UML類圖

這是專為實現排序功能而設計的策略模式UML類圖。因為存在很多排序演算法,該模式讓Client在排序時選擇適當的演算法。事實上,Java的集合框架就使用這個模式,實現了用來排序的Collections.sort()方法。不同的是,它不允許Client選擇排序演算法,而是讓它傳遞Comparator或Comparable介面的例項來指定比較策略。

讓我們來看看它們之間更多的相似之處:

  1. 新增新的狀態或策略都很容易,而且不需要修改使用它們的Context物件。
  2. 它們都讓你的程式碼符合OCP原則。在狀態模式和策略模式中,Context物件對修改是關閉的,新增新的狀態或策略,都不需要修改Context。
  3. 正如狀態模式中的Context會有初始狀態一樣,策略模式同樣有預設策略。
  4. 狀態模式以不同的狀態封裝不同的行為,而策略模式以不同的策略封裝不同的行為。
  5. 它們都依賴子類去實現相關行為。

不同之處

現在我們知道,狀態模式和策略模式的結構是相似的,但它們的意圖不同。讓我們重溫一下它們的主要不同之處:

  1. 策略模式封裝了一組相關演算法,它允許Client在執行時使用可互換的行為;狀態模式幫助一個類在不同的狀態顯示不同的行為。
  2. 狀態模式封裝了物件的狀態,而策略模式封裝演算法或策略。因為狀態是跟物件密切相關的,它不能被重用;而通過從Context中分離出策略或演算法,我們可以重用它們。
  3. 在狀態模式中,每個狀態通過持有Context的引用,來實現狀態轉移;但是每個策略都不持有Context的引用,它們只是被Context使用。
  4. 策略實現可以作為引數傳遞給使用它的物件,例如Collections.sort(),它的引數包含一個Comparator策略。另一方面,狀態是Context物件自己的一部分,隨著時間的推移,Context物件從一個狀態轉移到另一個狀態。
  5. 雖然它們都符合OCP原則,策略模式也符合SRP原則(單一職責原則),因為每個策略都封裝自己的演算法,且不依賴其他策略。一個策略的改變,並不會導致其他策略的變化。
  6. 另一個理論上的不同:策略模式定義了物件“怎麼做”的部分。例如,排序物件怎麼對資料排序。狀態模式定義了物件“是什麼”和“什麼時候做”的部分。例如,物件處於什麼狀態,什麼時候處在某個特定的狀態。
  7. 狀態模式中很好的定義了狀態轉移的次序;而策略模式並無此需要:Client可以自由的選擇任何策略。
  8. 一些常見的策略模式的例子是封裝演算法,例如排序演算法,加密演算法或者壓縮演算法。如果你看到你的程式碼需要使用不同型別的相關演算法,那麼考慮使用策略模式吧。而識別何時使用狀態模式是很簡單的:如果你需要管理狀態和狀態轉移,但不想使用大量巢狀的條件語句,那麼就是它了。
  9. 最後但最重要的一個不同之處是,策略的改變由Client完成;而狀態的改變,由Context或狀態自己。

相關推薦

Java狀態模式策略模式區別

Java開發者,要想恰當的使用狀態模式和策略模式,必須清楚的理解它們之間的區別。雖然狀態模式和策略模式擁有相似的結構,雖然它們都基於SOLID設計原則中的O(開閉原則),但是,它們的意圖是完全不同的。 策略模式通過封裝一組相關演算法,為Client提供執行時的靈活性。Cl

大話設計模式簡單工廠模式策略模式的商場收銀軟體例項的C++程式碼

策略模式是一種定義一系統演算法的方法,從概念上來看,所有這些演算法完成的都是相同的工作,只是具體的實現不同;策略模式可以以相同的方式呼叫所有的演算法,減少了各種演算法類與使用演算法類之間的耦合。 策略模式是用來封裝演算法的,但在實踐中,我們發現可以用它來封裝幾乎任何型別的規

《設計模式之禪》學習小結之責任鏈模式裝飾模式策略模式

一。責任鏈模式 責任鏈模式將多個處理物件聚合成一條鏈狀,被處理物件直接交由鏈頭處理,它會在鏈中被依次傳遞下去直到處理完成或到達最後一個處理物件為止。責任鏈模式可以將請求和處理分開,但是要注意鏈過長時的效能問題和鏈中節點數量問題。 二。裝飾模式 裝飾模式模式可以說是代理

(java)工廠模式策略模式

工廠模式 工廠模式是我們最常用的例項化物件模式了,是用工廠方法代替new操作的一種模式。工廠模式在Java程式系統可以說是隨處可見。因為工廠模式就相當於建立例項物件的new,我們經常要根據類Class生成例項物件,如A a=new A() 工廠模式也是用來建立例項物件的

代理模式 策略模式 看似相似有什麼不同

代理模式在使用的時候,使用的物件我們並不關係被代理者。 策略模式在使用的時候,我們使用的時候其實我們是知道指定的執行者。 如下 (注意傳參) 代理模式 Assist assist = new A

簡單工廠模式策略模式區別

首先看一下簡單工廠類和策略模式(Context)類中程式碼的區別: 簡單工廠類: //現金收費工廠類 class CashFactory { public static CashSuper createCashAccept(string type) { Cas

Java反射Class.forNameClassLoader的區別

前言 最近在面試過程中有被問到,在Java反射中Class.forName()載入類和使用ClassLoader載入類的區別。當時沒有想出來後來自己研究了一下就寫下來記錄一下。 解釋 在java中Class.forName()和ClassLoader都可以對類進行載入。ClassLo

【設計模式】(一)-簡單工廠模式策略模式

前言 最近開始和春哥,張鐸 ,銀平討論設計模式,成立了一個小菜變大鳥的小組,每天討論一個模式,並且把這個模式搞懂,每學一個新的模式,再回顧一下之前學的模式。這兩天學了簡單工廠模式和策略模式,發現兩個模式有很多相同之處,下面用商場促銷的例子來對兩個模式總結一下。 簡單工廠模式 1.

使用工廠模式策略模式重構複雜業務邏輯

專案組在和外部系統對接,花了好長一段時間對以前的列印邏輯做修改,修改了8次的bug,才實現了當前的外接系統的列印功能,上線的前一刻又發現此次的改動對以前的邏輯產生關聯影響,哎,不談了,原因很簡單,隨著外接系統的增多,實現的列印方式和功能已經很多了,而此時幾千行的程式碼看看已

三種工廠模式 策略模式 對比

一、引子 話說十年前,有一個爆發戶,他家有三輛汽車(Benz(賓士)、Bmw(寶馬)、Audi(奧迪)),還僱了司機為他開車。不過,爆發戶坐車時總是這樣:上Benz車後跟司機說“開賓士車!”,坐上Bmw後他說“開寶馬車!”,坐上 Audi後他說“開奧迪車!”。

橋接模式策略模式區別

  學習的過程中發現這兩個概念真的是有點區分不開,儘管可以很感性的說bridge模式要比strategy模式更復雜更具可塑性,更“高階”,但是如何清晰闡述兩者區別,卻實是有點困難。 套用偉人的一句話,站在巨人的肩膀上看得更遠,下邊三段分別來自CSDN論壇的貼子

java反射Class.forNameclassloader的區別(程式碼說話)

java中class.forName()和classLoader都可用來對類進行載入。 class.forName()前者除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊。 而classLoader只幹一件事情,就是將.class檔案

模板方法模式策略模式的相似點差異性

Template 模式採用繼承的方式實現演算法的異構,其關鍵點就是講通過演算法封裝在抽象基類中,並將不同的演算法實現細節放在子類中實現。Template模式符合面向物件系統分析和設計中的一個原則,依賴倒置原則,父類呼叫子類的操作,底層模組實現高層模組宣告的介面。這樣控制權在

工廠模式策略模式

一、工廠模式1.1簡單工廠模式實現計算器一般實現的計算器需要在客戶端進行邏輯判斷,在新增新的功能的時候需要修改很多的程式碼,而用簡單工廠模式可以將邏輯判斷的程式碼放在後臺,而且在新增新的功能的時候也很容易。在不用的應用中也能複用。首先建立Operation抽象類,將公有的方法

javaString、StringBufferStringBuilder的區別(簡單介紹)

情況 string 建議 code serializa 就是 同步 安全性 之間 簡單介紹 java中用於處理字符串常用的有三個類: 1、java.lang.String 2、java.lang.StringBuffer 3、java.lang.StrungBuilder

反射Class.forName classloader 的區別

https://blog.csdn.net/qq_27093465/article/details/52262340 java中class.forName()和classLoader都可用來對類進行載入。 類載入過程為: 載入-->連結-->初始化; 載入:通過累的全限定名獲取二進位制位

javalist、setmap 的區別

List的功能方法   實際上有兩種List: 一種是基本的ArrayList,其優點在於隨機訪問元素,另一種是更強大的LinkedList,它並不是為快速隨機訪問設計的,而是具有一套更通用的方法。   List : 次序是List最重要的特點:它保證維護元素特定的順序。List為Colle

JavaString 、StringBufferStringBuilder的區別

String 類是不可改變的,所以你一旦建立了 String 物件,那它的值就無法改變了 StringBuffer 和 StringBuilder 類相同點: StringBuffer 和 StringBuilder 類的物件能夠被多次的修改,並且不產生新的未使用物件。 Str

反射Class.forNameclassloader的區別?[中高]

相同點: java中class.forName()和classLoader都可用來對類進行載入。 不同點: class.forName()除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊。 而classLoader只幹一件事情,就是將.class檔

圖解JavaString、StringBufferStringBuilder的區別

圖解Java中String、StringBuffer和StringBuilder的區別 參考部落格:https://blog.csdn.net/weixin_41101173/article/details/79677982 一、Java中的 String 類——String 是字串常量 1、字