摘要:抽象策略策略類,通常是一個接口或者抽象類。策略模式設計圖改造原來的鴨子類代碼實現這里我們將類定義成抽象類,并把方法定義成抽象方法。策略模式提供了可以替換繼承關系的辦法。使用策略模式可以避免使用多重條件轉移語句。四參考資料設計模式
一、了解策略模式
1.1 什么是策略模式
策略模式 (Strategy Pattern) 是指對一系列的算法定義,并將每一個算法封裝起來,而且使它們還可以相互替換。此模式讓算法的變化獨立于使用算法的客戶。
1.2 策略模式組成結構
環境 (Context):持有一個策略類的引用,最終給客戶端調用。
抽象策略 (Strategy): 策略類,通常是一個接口或者抽象類。
具體策略 (ConcreteStrategy):實現了策略類中的策略方法,封裝相關的算法和行為。
1.3 策略模式 UML 圖解
1.4 策略模式應用場景
多個類只區別在表現行為不同,可以使用 Strategy 模式,在運行時動態選擇具體要執行的行為。
需要在不同情況下使用不同的策略 (算法),或者策略還可能在未來用其它方式來實現。
對客戶隱藏具體策略 (算法) 的實現細節,彼此完全獨立。
二、策略模式具體應用2.1 問題描述
模擬鴨子游戲:游戲中會出現各種鴨子,一邊游泳戲水、一邊呱呱叫,為了提高游戲的樂趣,加入了讓鴨子飛的功能。但是考慮到并不是所有的鴨子都會飛,比如像小孩子游泳時玩的橡皮鴨。現在讓你利用 OO 技術,設計鴨子相關的類。
2.2 使用繼承
我們可能想到使用繼承,在超類 Duck 中定義鴨子的相關方法,并實現其對應的動作,這樣就能讓所有鴨子都可以對應其 fly() 的動作。在定義橡皮鴨時,只需要覆蓋其父類 (Duck) 中的 fly() 方法即可。
如果我們還想加入誘餌鴨,這種鴨子既不會叫,也不會飛,那么我們就要繼承 Duck 類,重寫其中的 quack() 、display() 和 fly() 方法。
這種通過繼承的方法是可以解決問題,但是有很多的局限
代碼在多個子類中重復。
運行時的行為不容易改變。
很難知道鴨子的全部行為。
改變會牽一發動全身,造成其他鴨子不想要的改變。
2.3 使用接口
認識到上面繼承的不足,我們可能想到了另一種方式去解決這種問題,通過接口的方式去實現某些動作。把 fly() 和 quack() 方法從 Duck 類中抽取抽取出來,分別放在 Flyable 和 Quackable 接口中。
通過接口的方式是可以完成任務,但是這也確實是一個很笨的方式。因為對于很多種鴨子來說,它們大部分都會飛與呱呱叫,但是我們在定義它們類的時候都要去實現 Flyable 和 Quackable 接口,這樣一來重復的代碼更多了。
2.4 問題歸零
到這里我們知道使用繼承并不能很好的解決問題,因為鴨子的行為在子類中是不斷變化的,并且讓所有的鴨子都具有這些行為是不恰當的,比如橡皮鴨不具有飛的行為。通過接口的方式似乎還不錯,但是 Java 接口并不具備實現代碼,所以繼承接口并不能達到代碼復用的目的,一不小心,就可能造成新的錯誤!
幸運的是,有一個設計原則,恰好適用于這種狀況:找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。這樣以來,代碼變化引起的后果變少,系統將更有彈性。
2.5 策略模式登場
除了 fly() 和 quack() 方法之外,Duck 中的其他方法還算一切正常,沒有什么需要經常需要變化或修改的地方。所以除了 fly() 和 quack() 方法,我們不打算對 Duck 中的其他方法做太多處理。我們希望一切具有彈性,正是因為沒有彈性,上面兩種方法都被我們淘汰掉了。
比如說,我們要產生一個綠頭鴨的實例,并制定特定“類型”的飛行行為給它。我們可以在鴨子類中包含設定行為的方法,這樣就可以在“運行時”動態地“改變”綠頭鴨的飛行行為。
有了這些實現目標,于是就有了第二個設計原則:針對接口編程,而不是針對實現編程。
這里我們使用接口代表每個行為,比如說,FlyBehavior 與 QuackBehavior,而行為的每個實現都將實現其中一個接口。所以這次鴨子類不會去實現 Flyable 和 Quackable 接口,反而是由我們制造一組其他類專門實現 FlyBehavior 與 QuackBehavior,這就稱為“行為”類。由行為類而不是 Duck 類來實現該接口。
(1)策略模式設計圖
改造原來的鴨子類
(2) 代碼實現
這里我們將 Duck 類定義成抽象類,并把 display() 方法定義成抽象方法。
接口 QuackBehavior
package com.jas.strategy; public interface QuackBehavior { void quack(); }
接口 QuackBehavior 實現類 Quack(實現鴨子呱呱叫)
package com.jas.strategy; public class Quack implements QuackBehavior { @Override public void quack() { System.out.println("Quack!"); } }
接口 QuackBehavior 實現類 SQuack(實現鴨子橡皮吱吱叫)
package com.jas.strategy; public class SQuack implements QuackBehavior { @Override public void quack() { System.out.println("SQuack!"); } }
接口 QuackBehavior 實現類 MuteQuack(實現鴨子不會叫)
package com.jas.strategy; public class MuteQuack implements QuackBehavior { @Override public void quack() { System.out.println("Silence!"); } }
接口 FlyBehavior
package com.jas.strategy; public interface FlyBehavior { void fly(); }
接口 FlyBehavior 實現類 FlyWithWings(實現鴨子飛)
package com.jas.strategy; public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("I"m flying!"); } }
接口 FlyBehavior 實現類 FlyNoWay(實現鴨子不會飛)
package com.jas.strategy; public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("I can"t fly!"); } }
Duck 類
package com.jas.strategy; public abstract class Duck { private QuackBehavior quackBehavior; private FlyBehavior flyBehavior; public void swim(){ System.out.println("All ducks float."); } public abstract void display(); public void performQuack(){ quackBehavior.quack(); } public void performFly(){ flyBehavior.fly(); } public void setQuackBehavior(QuackBehavior quackBehavior){ this.quackBehavior = quackBehavior; } public void setFlyBehavior(FlyBehavior flyBehavior){ this.flyBehavior = flyBehavior; } }
測試類 RubberDuck
package com.jas.strategy; public class RubberDuck extends Duck { @Override public void display() { System.out.println("Rubber Duck"); } public static void main(String[] args) { Duck rubberDuck = new RubberDuck(); //橡皮鴨實例 rubberDuck.setQuackBehavior(new SQuack()); //橡皮鴨吱吱叫 rubberDuck.setFlyBehavior(new FlyNoWay()); //橡皮鴨不會飛 rubberDuck.performQuack(); rubberDuck.performFly(); } } //輸出 //SQuack! //I can"t fly!
2.6 從策略模式組成結構對問題進行總結
三、策略模式總結3.1 策略模式的優缺點
優點
策略模式提供了管理相關的算法族的辦法,從而避免重復的代碼。
策略模式提供了可以替換繼承關系的辦法。因為繼承使得動態改變算法或行為變得不可能。
使用策略模式可以避免使用多重條件轉移語句。
缺點
客戶端必須知道所有的策略類,并自行決定使用哪一個策略類。
策略模式造成很多的策略類,每個具體策略類都會產生一個新類。
四、參考資料《Head First 設計模式》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77250.html
摘要:我們今天也來做一個萬能遙控器設計模式適配器模式將一個類的接口轉換成客戶希望的另外一個接口。今天要介紹的仍然是創建型設計模式的一種建造者模式。設計模式的理論知識固然重要,但 計算機程序的思維邏輯 (54) - 剖析 Collections - 設計模式 上節我們提到,類 Collections 中大概有兩類功能,第一類是對容器接口對象進行操作,第二類是返回一個容器接口對象,上節我們介紹了...
摘要:孫臏心里一萬個草泥馬在奔騰,差點沒噎死自己滾一邊去,我們這盤跟他賽馬開始,策略模式上場。在設計模式之禪中的提出通過策略枚舉和反射機制對策略模式進行改良,膜拜了但是要添加或淘汰策略,還是得去對枚舉進行修改,也不符合開閉原則。 今天給大家說說田忌賽馬的故事。如有雷同,純屬巧合!話說在戰國時期,群雄割據,硝煙四起,茶余飯后還是少不了娛樂活動的,其中賽馬是最火爆的。一天,孫臏看到田忌像個死雞似...
摘要:下面我們就來介紹怎么用策略模式來解決這個問題。結果很快的跳很快的跑紅藍相間的超人狗不會跳不會跑紅藍相間的超人狗總結策略模式就是把所有的可變的行為都抽取出來放到接口中,然后定義很多的行為類去實現接口。 策略模式就是定義了一系列的的算法,將它們都單獨封裝起來,讓他們之間可以相互替換,可以讓算法的變化獨立于使用算法的客戶。 首先創建一個Dog父類,有run方法控制跑,jump方法控制跳,c...
閱讀 2183·2021-11-19 09:40
閱讀 1919·2021-11-08 13:24
閱讀 2453·2021-10-18 13:24
閱讀 2858·2021-10-11 10:57
閱讀 3578·2021-09-22 15:42
閱讀 1114·2019-08-29 17:11
閱讀 2528·2019-08-29 16:11
閱讀 2421·2019-08-29 11:11