也稱為:Strategy
#策略模式是一種行為設計模式,它能讓你定義一系列演算法,並將每種演算法分別放入獨立的類別中,以使演算法的物件能夠相互替換。
一天,你打算為遊客建立導覽程式。該程式的核心功能是提供美觀的地圖,以幫助用戶在任何城市中快速定位。
用戶期待的程式新功能是自動路線規劃:他們希望輸入地址後就能在地圖上看到前往目的地的最快路線。
程式的首個版本只能規劃公路路線。駕車旅行的人們對此非常滿意。但很顯然,並非所有人都會在度假時開車。因此你在下次更新時加入了規劃步行路線的功能。此後,你又增加了規劃大眾運輸路線的功能。
而這只是個開始。不久後,你又要為騎乘者規劃路線。又過了一段時間,你又要為遊覽城市中的所有景點規劃路線。
導覽程式碼將變得非常臃腫。
儘管從商業角度來看,這款應用非常成功,但其技術部分卻讓你非常頭疼:每次添加新的路線規劃演算法後,導遊應用中主要類別的體積就會增加一倍。終於在某個時候,你覺得自己沒辦法繼續維護這堆程式碼了。
無論是修復簡單缺陷還是微調街道權重,對某個演算法進行任何修改都會影響整個類,從而增加在已有正常運行程式碼中引入錯誤的風險。
此外,團隊合作將變得低效。如果你在應用程式成功發布後招募了團隊成員,他們會抱怨在合併衝突的工作上花了太多時間。在實現新功能的過程中,你的團隊需要修改同一個巨大的類,這樣他們所寫的程式碼彼此之間就可能會出現衝突。
策略模式建議找出負責用許多不同方式完成特定任務的類,然後將其中的演算法抽取到一組被稱為策略的獨立類中。
名為上下文的原始類別必須包含一個成員變數來儲存對於每種策略的參考。上下文並不會執行任務,而是將工作委派給已連線的策略物件。
上下文不負責選擇符合任務需求的演算法——客戶端會將所需策略傳遞給上下文。實際上,上下文並不十分了解策略,它會透過相同的通用介面與所有策略進行交互,而該介面只需暴露一個方法來觸發所選策略中封裝的演算法即可。
因此,上下文可獨立於具體策略。這樣你就可在不修改上下文程式碼或其他策略的情況下加入新演算法或修改已有演算法了。
路線規劃策略。
在導覽應用中,每個路線規劃演算法都可被抽取到只有一個buildRoute
產生路線方法的獨立類別中。此方法接收起點和終點作為參數,並傳迴路線中途點的集合。
即使傳遞給每個路徑規劃類別的參數一模一樣,其所建立的路線也可能完全不同。主要導遊類別的主要工作是在地圖上渲染一系列中途點,不會在意如何選擇演算法。此類別中還有一個用於切換目前路徑規劃策略的方法,因此用戶端(例如使用者介面中的按鈕)可用其他策略來取代目前選擇的路徑規劃行為。
各種前往機場的旅遊策略
假如你需要前往機場。你可以選擇搭乘公車、預約計程車或騎自行車。這些就是你的旅遊策略。你可以根據預算或時間等因素來選擇其中一種策略。
上下文(Context)維護指向特定策略的引用,且僅透過策略介面與該物件進行交流。
策略(Strategy)介面是所有特定策略的通用接口,它聲明了一個上下文用於執行策略的方法。
具體策略(Concrete Strategies)實作了上下文所用演算法的各種不同變體。
當上下文需要執行演算法時,它會在其已連接的策略物件上呼叫執行方法。上下文不清楚其所涉及的策略類型與演算法的執行方式。
客戶端(Client)會建立一個特定策略物件並將其傳遞給上下文。上下文則會提供一個設定器以便用戶端在執行時取代相關聯的策略。
在本例中,上下文使用了多個策略來執行不同的計算操作。
// 策略接口声明了某个算法各个不同版本间所共有的操作。上下文会使用该接口来 // 调用有具体策略定义的算法。 interface Strategy is method execute(a, b) // 具体策略会在遵循策略基础接口的情况下实现算法。该接口实现了它们在上下文 // 中的互换性。 class ConcreteStrategyAdd implements Strategy is method execute(a, b) is return a + b class ConcreteStrategySubtract implements Strategy is method execute(a, b) is return a - b class ConcreteStrategyMultiply implements Strategy is method execute(a, b) is return a * b // 上下文定义了客户端关注的接口。 class Context is // 上下文会维护指向某个策略对象的引用。上下文不知晓策略的具体类。上下 // 文必须通过策略接口来与所有策略进行交互。 private strategy: Strategy // 上下文通常会通过构造函数来接收策略对象,同时还提供设置器以便在运行 // 时切换策略。 method setStrategy(Strategy strategy) is this.strategy = strategy // 上下文会将一些工作委派给策略对象,而不是自行实现不同版本的算法。 method executeStrategy(int a, int b) is return strategy.execute(a, b) // 客户端代码会选择具体策略并将其传递给上下文。客户端必须知晓策略之间的差 // 异,才能做出正确的选择。 class ExampleApplication is method main() is 创建上下文对象。 读取第一个数。 读取最后一个数。 从用户输入中读取期望进行的行为。 if (action == addition) then context.setStrategy(new ConcreteStrategyAdd()) if (action == subtraction) then context.setStrategy(new ConcreteStrategySubtract()) if (action == multiplication) then context.setStrategy(new ConcreteStrategyMultiply()) result = context.executeStrategy(First number, Second number) 打印结果。
當你想使用物件中各種不同的演算法變體,並希望在運行時切換演算法時,可使用策略模式。
策略模式讓你能夠將物件關聯到可以不同方式執行特定子任務的不同子對象,從而以間接方式在運行時更改對象行為。
當你有許多僅在執行某些行為時略有不同的相似類別時,可使用策略模式。
策略模式讓你能將不同行為抽取到一個獨立類別層次結構中,並將原始類別組合成同一個,從而減少重複程式碼。
如果演算法在上下文的邏輯中不是特別重要,使用該模式能將類別的業務邏輯與其演算法實作細節隔離。
策略模式讓你能將各種演算法的程式碼、內部資料和依賴關係與其他程式碼隔離。不同客戶端可透過一個簡單介面執行演算法,並能在運行時進行切換。
當類別中使用了複雜條件運算子以在相同演算法的不同變體中切換時,可使用此模式。
策略模式將所有繼承自相同介面的演算法抽取到獨立類別中,因此不再需要條件語句。原始物件並不會實現所有演算法的變體,而是將執行工作委派給其中的一個獨立演算法物件。
從上下文類別中找出修改頻率較高的演算法(也可能是用於在運行時選擇某個演算法變體的複雜條件運算符)。
宣告該演算法所有變體的通用策略介面。
將演算法逐一抽取到各自的類別中,它們都必須實作策略介面。
在上下文類別中加入一個成員變數用於保存對於策略物件的參考。然後提供設定器以修改該成員變數。上下文僅可透過策略介面同策略物件進行交互,如有需要還可定義一個介面來讓策略存取其資料。
客戶端必須將上下文類別與對應策略關聯,使上下文可以預期的方式完成其主要工作。
你可以在執行時間切換物件內的演算法。
你可以將演算法的實作和使用演算法的程式碼隔離開來。
你可以用組合來取代繼承。
開閉原則。你無需對上下文進行修改就能夠引入新的策略。
如果你的演算法極少改變,那麼沒有任何理由引入新的類別和介面。使用該模式只會讓程式過於複雜。
客戶端必須知道策略間的不同——它需要選擇合適的策略。
許多現代程式語言支援函數類型功能,允許你在一組匿名函數中實作不同版本的演算法。這樣,你使用這些函數的方式就和使用策略物件時完全相同,無需借助額外的類別和介面來保持程式碼簡潔。
橋接模式、狀態模式和策略模式(在某種程度上包括適配器模式)模式的介面非常相似。實際上,它們都基於組合模式——即將工作委派給其他對象,不過也各自解決了不同的問題。模式並不是只是以特定方式組織程式碼的配方,你還可以使用它們來和其他開發者討論模式所解決的問題。
指令模式和策略看起來很像,因為兩者都能透過某些行為來參數化物件。但是,它們的意圖有非常大的不同。
你可以使用指令來將任何動作轉換為物件。操作的參數將成為物件的成員變數。你可以透過轉換來延遲操作的執行、將操作放入佇列、保存歷史命令或向遠端服務發送命令等。
另一方面,策略通常可用來描述完成某件事的不同方式,讓你能夠在同一個上下文類別中切換演算法。
裝飾模式可讓你改變物件的外表,策略則讓你能夠改變其本質。
模板方法模式基於繼承機制:它允許你透過擴展子類別中的部分內容來改變部分演算法。策略是基於組合機制:你可以透過對對應行為提供不同的策略來改變物件的部分行為。模板方法在類別層次上運作,因此它是靜態的。策略在物件層次上運作,因此允許在運行時切換行為。
狀態可視為策略的擴充。兩者都基於組合機制:它們都透過將部分工作委派給「幫手」物件來改變其在不同情境下的行為。策略使得這些物件彼此之間完全獨立,它們不知道其他物件的存在。但狀態模式並沒有限制具體狀態之間的依賴,並且允許它們自行改變在不同情境下的狀態。
以上是java設計模式的策略模式是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!