策略模式在生活中體現不少。java
咱們要去旅遊,咱們能夠選擇不一樣的出行方式:飛機,火車,大巴,自駕等,這是不一樣的策略。算法
雙十一當當網購買滿減活動,滿 100 減 50,滿 200 減 100,滿 400 減 250 等,這也是不一樣的策略。設計模式
抑或是咱們在追求女生時,針對不一樣性格的女孩子採用不一樣的方式,這仍是不一樣的策略。安全
策略模式在程序中的體現依然淋漓盡致。框架
好比咱們的圖片加載,Android 上有 Fresco
,Picasso
,Glide
,Universal-Image-Loader
等,iOS 上有 SDWebImage
、AFNetworking
、FastImageCache
等。ide
因此,假設讓你來設計一個圖片加載上層框架,要求能夠底層可使用 A B 兩種加載策略,你會怎麼作呢?學習
// 加載類A public class ImageLoadServiceA { public void loadImage() { System.out.println("使用 A 加載框架"); } } // 加載類B public class ImageLoadServiceB { public void loadImage() { System.out.println("使用 B 加載框架"); } } // 使用 public void loadNetImage(boolean useA) { if(useA){ new ImageLoadServiceA().loadImage();// 使用A加載方式 } else { new ImageLoadServiceB().loadImage();// 使用B加載方式 } }
能夠看到,上述經過一個 useA
參數判斷是否使用 A 框架,爲 true
使用 A,不然使用 B 框架進行加載。動畫
但假設咱們如今須要再支持一個 C 框架的使用,你可能想到了,那就再加一個 boolean 參數 useB
便可,或者直接使用一個 int 參數 loadType
,宏定義 0 表明 A 框架,1 表明 B 框架,2 表明 C 框架,這樣若是須要增長方式則更新取值便可。this
設計模式不過是咱們寫程序的招式,因爲以前你們可能還學習過了簡單工廠模式,咱們不妨在這裏進行實戰。設計
// 抽象圖片加載類 public abstract class ImageLoadService { public abstract void loadImage(); } // 具體加載類A public class ImageLoadServiceA extends ImageLoadService { @Override public void loadImage() { System.out.println("使用 A 加載框架"); } } //具體加載類B public class ImageLoadServiceB extends ImageLoadService { @Override public void loadImage() { System.out.println("使用 B 加載框架"); } } //具體加載類C public class ImageLoadServiceC extends ImageLoadService { @Override public void loadImage() { System.out.println("使用 C 加載框架"); } } public class ImageLoadFactory { public static ImageLoadService create(int loadType) { ImageLoadService loadService = null; switch (loadType) { case 0: loadService = new ImageLoadServiceA(); break; case 1: loadService = new ImageLoadServiceB(); break; case 2: loadService = new ImageLoadServiceC(); break; } return loadService; } } // 使用 public void loadNetImage(int loadType) { ImageLoadFactory.create(loadType).loadImage(); }
能夠看到,咱們使用簡單工廠模式後,在處理新增其餘加載方式的問題的時候,不會再去影響原有的加載類代碼,若是新增一種加載方式的話,咱們只須要新增 ImageLoadXXX
類,實現 loadImage()
加載方法,再修改工廠類 ImageLoadFactory
便可。
相信你也發現了,這個方式只能解決對象的建立問題,咱們每次新增方式的時候都會新增一個類,並且須要對工廠類進行代碼修改,顯然是違反了開閉原則。
人生到處有策略,上面的不一樣的加載方式其實就是不一樣的「策略」。
策略模式是對 算法的封裝,它將每個算法封裝到具備共同接口的獨立的類中,從而使得它們能夠獨立變換。
要學習一個設計模式,先要學會臨摹,因此上面的需求,咱們能夠實現爲:
public interface ImageLoadStrategy { void loadImage() ; }
// 具體加載類A public class ImageLoadStrategyA implements ImageLoadStrategy { @Override public void loadImage() { System.out.println("使用 A 加載框架"); } } //具體加載類B public class ImageLoadStrategyB implements ImageLoadStrategy { @Override public void loadImage() { System.out.println("使用 B 加載框架"); } } //具體加載類C public class ImageLoadStrategyC implements ImageLoadStrategy { @Override public void loadImage() { System.out.println("使用 C 加載框架"); } }
public class ContextImageLoadStrategy { private ImageLoadStrategy strategy ; public ContextImageLoadStrategy(ImageLoadStrategy strategy){ this.strategy = strategy ; } public void loadImage(){ strategy.loadImage(); } }
public void loadImage(ImageLoadStrategy imageLoadStrategy){ ContextImageLoadStrategy contextStrategy = new ContextImageLoadStrategy(imageLoadStrategy); contextStrategy.loadImage(); }
注意: 策略的核心不是如何實現算法,而是如何更優雅的把這些算法組織起來,讓客戶端很是好調用「雖然策略很是多,能夠自由切換,可是同一時間客戶端只能調用一個策略,其實也很好理解,你不可能同時既坐飛機,又坐火車」。
if-else
或者 switch
)。你有想到如何解決「客戶端必須知道全部的策略類」這個缺點麼?
if-else
或者 switch
語句來選擇具體行爲時。使用策略模式把這些行爲獨立到具體的策略類中,能夠避免多重選擇的結構。想必你們已經很清楚上面的策略模式了,下面源碼中用到策略模式了嗎?
ListView
的 ArrayAdapter
、SimpleAdapter
;總的來講,策略模式還算咱們項目開發中會使用很是頻繁的模式,你學會了麼?若有疑問,請在評論區留言。