掃盲:策略模式,成事兒還須要策略

什麼是策略模式?

生活中的策略

策略模式在生活中體現不少。java

咱們要去旅遊,咱們能夠選擇不一樣的出行方式:飛機,火車,大巴,自駕等,這是不一樣的策略。算法

雙十一當當網購買滿減活動,滿 100 減 50,滿 200 減 100,滿 400 減 250 等,這也是不一樣的策略。設計模式

抑或是咱們在追求女生時,針對不一樣性格的女孩子採用不一樣的方式,這仍是不一樣的策略。安全

程序中的策略

策略模式在程序中的體現依然淋漓盡致。框架

好比咱們的圖片加載,Android 上有 FrescoPicassoGlideUniversal-Image-Loader 等,iOS 上有 SDWebImageAFNetworkingFastImageCache 等。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 便可。

相信你也發現了,這個方式只能解決對象的建立問題,咱們每次新增方式的時候都會新增一個類,並且須要對工廠類進行代碼修改,顯然是違反了開閉原則。

策略模式

人生到處有策略,上面的不一樣的加載方式其實就是不一樣的「策略」。

策略模式是對 算法的封裝,它將每個算法封裝到具備共同接口的獨立的類中,從而使得它們能夠獨立變換。

策略模式的特色

  • 是一種行爲模式,對算法封裝,使得客戶端獨立於各個策略;
  • 擴展性強,添加策略無非就是添加一個具體的實現類而已,代價很是低;

策略模式的結構


類圖

策略模式作實現

要學習一個設計模式,先要學會臨摹,因此上面的需求,咱們能夠實現爲:

  1. 定義抽象策略
public interface ImageLoadStrategy {
    void loadImage() ;
}
  1. 定義具體的策略
// 具體加載類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 加載框架");
    }
}
  1. 定義上下文,選擇方式
public class ContextImageLoadStrategy {

    private ImageLoadStrategy strategy ;

    public ContextImageLoadStrategy(ImageLoadStrategy strategy){
        this.strategy = strategy ;
    }

    public void loadImage(){
        strategy.loadImage();
    }
}
  1. 使用
public void loadImage(ImageLoadStrategy imageLoadStrategy){
    ContextImageLoadStrategy contextStrategy = new ContextImageLoadStrategy(imageLoadStrategy);
    contextStrategy.loadImage();
}

注意: 策略的核心不是如何實現算法,而是如何更優雅的把這些算法組織起來,讓客戶端很是好調用「雖然策略很是多,能夠自由切換,可是同一時間客戶端只能調用一個策略,其實也很好理解,你不可能同時既坐飛機,又坐火車」。

策略模式的優勢

  • 策略類能夠互相替換
    因爲策略類都實現同一個接口,所以他們可以互相替換。
  • 耦合度低,方便擴展
    增長一個新的策略只須要添加一個具體的策略類便可,基本不須要改變原有的代碼,符合開閉原則。
  • 避免使用多重條件選擇語句(if-else 或者 switch)。

策略模式的缺點

  • 策略的增多會致使子類的也會變多。好比上方再增長加載方式必須增長類。
  • 客戶端必須知道全部的策略類,並自行決定使用哪個策略類。好比上方必須知道有哪些加載策略,這樣咱們才能調用到正確的加載方式。

你有想到如何解決「客戶端必須知道全部的策略類」這個缺點麼?

策略模式的應用場景

  • 同一個問題具備不一樣算法時,即僅僅是具體的實現細節不一樣時,如各類排序算法等等。
  • 對客戶隱藏具體策略(算法)的實現細節,彼此徹底獨立;提升算法的保密性與安全性。
  • 一個類擁有不少行爲,而又須要使用 if-else 或者 switch 語句來選擇具體行爲時。使用策略模式把這些行爲獨立到具體的策略類中,能夠避免多重選擇的結構。

源碼中的策略模式

想必你們已經很清楚上面的策略模式了,下面源碼中用到策略模式了嗎?

  • Android 的動畫插值器;
  • Android 中 ListViewArrayAdapterSimpleAdapter

寫在最後

總的來講,策略模式還算咱們項目開發中會使用很是頻繁的模式,你學會了麼?若有疑問,請在評論區留言。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息