本文解決問題
- 什么是策略模式职抡?
- 策略模式的優(yōu)缺點以及策略模式解決了什么痛點
- 策略模式的適用環(huán)境
什么是策略模式亩歹?
策略模式(Strategy Pattern):定義一系列算法纫事,將每一個算法封裝起來册着,并讓它們可以相互替換褐着。策略模式讓算法獨立于使用它的客戶而變化,也稱為政策模式(Policy)豆挽。
策略模式是一種對象行為型模式育谬。
說定義恐怕總會令人迷惑,其實這里的算法就是我們?nèi)粘Kf的行為帮哈,舉個栗子:
這是一個模擬鴨子游戲:游戲中會出現(xiàn)各種鴨子膛檀,一邊游泳,一邊叫娘侍。
這個應(yīng)用用的是OO技術(shù)有一個鴨子超類(superclass)宿刮,并讓各種鴨子繼承此類。
public abstract class Duck {
public Duck() {}
abstract void display();
public void quack() {}
public void swim() {}
}
public class MallardDuck extends Duck {
//外觀是綠頭鴨
public MallardDuck() {}
public void display() {}
}
public class RedHeadDuck extends Duck {
public RedHeadDuck() {}
public void display() {}
}
但是產(chǎn)品經(jīng)理組織了一場頭腦風暴私蕾,然后決定要讓鴨子們會飛,我們怎么做胡桃?程序猿們說 很簡單于是
public class Duck {
public Duck() {}
public void quack() {}
public void swim() {}
public void fly(){}
}
所有的鴨子都會飛了踩叭,但是……,他們的游戲里面有一只橡皮鴨翠胰,產(chǎn)品經(jīng)理攤手表示容贝,橡皮鴨是為什么會飛的。之景。斤富。。這時候你會怎么辦锻狗?
OO來說我們繼承覆蓋就好了
public class RubberDuck extends Duck {
public void display() {};
public void quack(){};
public void fly(){
//什么都不做
}
}
但是如果以后加入鐵鴨子怎么辦满力?不會飛也不會叫
那下面我們用OO中的接口如何?也就是說把fly()quack()寫成接口轻纪,下面的鴨子進行繼承油额。會有什么問題呢?
如果是你你會怎么辦刻帚?
采用良好的00軟件設(shè)計原則:
- 原則一:
找出應(yīng)用中可能需要變化的地方潦嘶,把它們獨立出來,不要和那些不需要變化的代碼混在一起崇众,這時候你就可以很好的修改或者擴展這部分掂僵,而不影響不需要變化的其他部分航厚。
到底哪一些是Duck類變得以及不變的?
- fly()與quack()會隨著不同而改變
- 你沒有辦法開始就知道锰蓬,但是可以再改需求的時候慢慢修改提煉
- 原則二:
針對接口編程幔睬,而不是針對實現(xiàn)編程
這個對于我們OO來說很需要了解,我目前總是針對實現(xiàn)編程而不是接口編程互妓。在栗子中怎么實現(xiàn)呢溪窒?那就是鴨子的行為將被放在分開的類中,專門提供某行為的接口的實現(xiàn)冯勉,鴨子的類就不需要知道行為的實現(xiàn)細節(jié)
舉個栗子:
public interface FlyBehavior {
public void fly();
}
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("I'm flying!!");
}
}
public class FlyNoWay implements FlyBehavior {
public void fly() {
System.out.println("I can't fly");
}
}
public interface QuackBehavior {
public void quack();
}
public class Quack implements QuackBehavior {
public void quack() {
//呱呱叫
System.out.println("Quack");
}
}
public class Squeak implements QuackBehavior {
public void quack() {
//橡皮鴨子吱吱叫
System.out.println("Squeak");
}
}
public class MuteQuack implements QuackBehavior {
public void quack() {
//什么都不做澈蚌,我不會叫
System.out.println("<< Silence >>");
}
}
那這些有什么好處?對了行為單獨一個類灼狰,實現(xiàn)了解耦宛瞄,這些行為和鴨子無關(guān)了,以后Nathan要什么的鴨子交胚,我們程序猿都可以給他了份汗。
這時候有個問題,我們要在什么時候分離封裝呢蝴簇?
解耦很清晰杯活,可是我們要怎么整合起來呢?讓鴨子更像一個鴨子熬词,先要在duck加兩個實體變量
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("All ducks float, even decoys!");
}
}
public class MallardDuck extends Duck {
public MallardDuck() {
//在構(gòu)造綠頭鴨的時候裝配上叫和飛的行為旁钧,這個綠頭鴨就真的會飛和叫了
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
public void display() {
System.out.println("I'm a real Mallard duck");
}
}
編寫好了,如何測試呢互拾?
public class MiniDuckSimulator {
public static void main(String[] args) {
MallardDuck mallard = new MallardDuck();
RubberDuck rubberDuckie = new RubberDuck();
DecoyDuck decoy = new DecoyDuck();
mallard.performQuack();
rubberDuckie.performQuack();
decoy.performQuack();
}
}
講了這么多歪今,我們從新的梳理一下,到底整體的一個架構(gòu)是什么樣子的颜矿,這時候請不要把鴨子的行為說成行為寄猩,我們把行為想象成一族算法,這樣行為是不是就可以放在很多地方了骑疆?
- 原則三
多用組合田篇,少用繼承。
上面我們看了組合建立系統(tǒng)的具有很大的彈性封断,可以把算法族封裝成類斯辰,還可以隨意組合,只要符合正確的接口坡疼。
以后要做什么捕捉鴨子的鴨鳴器繼承一個算法就可以很快實現(xiàn)彬呻。
上述其實講解OO原則的時候你已經(jīng)學(xué)會了策略模式。
策略模式的優(yōu)點
- 策略模式提供了對“開閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇算法或行為闸氮,也可以靈活地增加新的算法或行為剪况。
- 策略模式提供了管理相關(guān)的算法族的辦法。
- 策略模式提供了可以替換繼承關(guān)系的辦法蒲跨。
- 使用策略模式可以避免使用多重條件轉(zhuǎn)移語句译断。
策略模式的缺點
- 客戶端必須知道所有的策略類,并自行決定使用哪一個策略類或悲。
- 策略模式將造成產(chǎn)生很多策略類孙咪,可以通過使用享元模式在一定程度上減少對象的數(shù)量。
策略模式的適用范圍
做面向?qū)ο笤O(shè)計的巡语,對策略模式一定很熟悉翎蹈,因為它實質(zhì)上就是面向?qū)ο笾械睦^承和多態(tài),在看完策略模式的通用代碼后男公,我想荤堪,即使之前從來沒有聽說過策略模式,在開發(fā)過程中也一定使用過它吧枢赔?至少在在以下兩種情況下澄阳,大家可以考慮使用策略模式,
- 幾個類的主要邏輯相同踏拜,只在部分邏輯的算法和行為上稍有區(qū)別的情況碎赢。
- 有幾種相似的行為,或者說算法速梗,客戶端需要動態(tài)地決定使用哪一種揩抡,那么可以使用策略模式,將這些算法封裝起來供客戶端調(diào)用镀琉。
? 策略模式是一種簡單常用的模式,我們在進行開發(fā)的時候蕊唐,會經(jīng)常有意無意地使用它屋摔,一般來說,策略模式不會單獨使用替梨,跟模版方法模式钓试、工廠模式等混合使用的情況比較多。
- 如果在一個系統(tǒng)里面有許多類副瀑,它們之間的區(qū)別僅在于它們的行為弓熏,那么使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為。
- 一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種糠睡。
- 如果一個對象有很多的行為挽鞠,如果不用恰當?shù)哪J剑@些行為就只好使用多重的條件選擇語句來實現(xiàn)。
- 不希望客戶端知道復(fù)雜的信认、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)材义,在具體策略類中封裝算法和相關(guān)的數(shù)據(jù)結(jié)構(gòu),提高算法的保密性與安全性嫁赏。