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

什么是策略模式缭黔?

生活中的策略

策略模式在生活中體現(xiàn)很多食茎。

我們要去旅游,我們可以選擇不同的出行方式:飛機(jī)馏谨,火車别渔,大巴,自駕等惧互,這是不同的策略哎媚。

雙十一當(dāng)當(dāng)網(wǎng)購買滿減活動,滿 100 減 50喊儡,滿 200 減 100拨与,滿 400 減 250 等,這也是不同的策略艾猜。

抑或是我們在追求女生時买喧,針對不同性格的女孩子采用不同的方式,這還是不同的策略匆赃。

程序中的策略

策略模式在程序中的體現(xiàn)依然淋漓盡致淤毛。

比如我們的圖片加載,Android 上有 Fresco算柳,Picasso低淡,GlideUniversal-Image-Loader 等,iOS 上有 SDWebImage蔗蹋、AFNetworking事期、FastImageCache 等。

所以纸颜,假設(shè)讓你來設(shè)計一個圖片加載上層框架兽泣,要求可以底層可以使用 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 參數(shù)判斷是否使用 A 框架,為 true 使用 A涮较,否則使用 B 框架進(jìn)行加載稠鼻。

使用簡單工廠模式應(yīng)對

但假設(shè)我們現(xiàn)在需要再支持一個 C 框架的使用,你可能想到了狂票,那就再加一個 boolean 參數(shù) useB 即可候齿,或者直接使用一個 int 參數(shù) loadType,宏定義 0 代表 A 框架闺属,1 代表 B 框架慌盯,2 代表 C 框架,這樣如果需要增加方式則更新取值即可掂器。

設(shè)計模式不過是我們寫程序的招式亚皂,由于之前大家可能還學(xué)習(xí)過了簡單工廠模式,我們不妨在這里進(jìn)行實(shí)戰(zhàn)国瓮。

// 抽象圖片加載類 
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 類孵睬,實(shí)現(xiàn) loadImage() 加載方法播歼,再修改工廠類 ImageLoadFactory 即可。

相信你也發(fā)現(xiàn)了肪康,這個方式只能解決對象的創(chuàng)建問題荚恶,我們每次新增方式的時候都會新增一個類,而且需要對工廠類進(jìn)行代碼修改磷支,顯然是違反了開閉原則谒撼。

策略模式

人生處處有策略,上面的不同的加載方式其實(shí)就是不同的「策略」雾狈。

策略模式是對 算法的封裝廓潜,它將每一個算法封裝到具有共同接口的獨(dú)立的類中,從而使得它們可以獨(dú)立變換。

策略模式的特點(diǎn)

  • 是一種行為模式辩蛋,對算法封裝呻畸,使得客戶端獨(dú)立于各個策略;
  • 擴(kuò)展性強(qiáng)悼院,添加策略無非就是添加一個具體的實(shí)現(xiàn)類而已伤为,代價非常低;

策略模式的結(jié)構(gòu)


類圖

策略模式做實(shí)現(xiàn)

要學(xué)習(xí)一個設(shè)計模式据途,先要學(xué)會臨摹绞愚,所以上面的需求,我們可以實(shí)現(xiàn)為:

  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();
}   

注意: 策略的核心不是如何實(shí)現(xiàn)算法位衩,而是如何更優(yōu)雅的把這些算法組織起來,讓客戶端非常好調(diào)用「雖然策略非常多熔萧,可以自由切換糖驴,但是同一時間客戶端只能調(diào)用一個策略,其實(shí)也很好理解佛致,你不可能同時既坐飛機(jī)贮缕,又坐火車」。

策略模式的優(yōu)點(diǎn)

  • 策略類可以互相替換
    由于策略類都實(shí)現(xiàn)同一個接口晌杰,因此他們能夠互相替換跷睦。
  • 耦合度低,方便擴(kuò)展
    增加一個新的策略只需要添加一個具體的策略類即可肋演,基本不需要改變原有的代碼,符合開閉原則烂琴。
  • 避免使用多重條件選擇語句(if-else 或者 switch)爹殊。

策略模式的缺點(diǎn)

  • 策略的增多會導(dǎo)致子類的也會變多。比如上方再增加加載方式必須增加類奸绷。
  • 客戶端必須知道所有的策略類梗夸,并自行決定使用哪一個策略類。比如上方必須知道有哪些加載策略号醉,這樣我們才能調(diào)用到正確的加載方式反症。

你有想到如何解決「客戶端必須知道所有的策略類」這個缺點(diǎn)么?

策略模式的應(yīng)用場景

  • 同一個問題具有不同算法時畔派,即僅僅是具體的實(shí)現(xiàn)細(xì)節(jié)不同時铅碍,如各種排序算法等等。
  • 對客戶隱藏具體策略(算法)的實(shí)現(xiàn)細(xì)節(jié)线椰,彼此完全獨(dú)立胞谈;提高算法的保密性與安全性。
  • 一個類擁有很多行為,而又需要使用 if-else 或者 switch 語句來選擇具體行為時烦绳。使用策略模式把這些行為獨(dú)立到具體的策略類中卿捎,可以避免多重選擇的結(jié)構(gòu)。

源碼中的策略模式

想必大家已經(jīng)很清楚上面的策略模式了径密,下面源碼中用到策略模式了嗎午阵?

  • Android 的動畫插值器;
  • Android 中 ListViewArrayAdapter享扔、SimpleAdapter趟庄;

寫在最后

總的來說,策略模式還算我們項(xiàng)目開發(fā)中會使用非常頻繁的模式伪很,你學(xué)會了么戚啥?如有疑問,請在評論區(qū)留言锉试。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末猫十,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子呆盖,更是在濱河造成了極大的恐慌拖云,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件应又,死亡現(xiàn)場離奇詭異宙项,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)株扛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門尤筐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洞就,你說我怎么就攤上這事盆繁。” “怎么了旬蟋?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵油昂,是天一觀的道長。 經(jīng)常有香客問我倾贰,道長冕碟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任匆浙,我火速辦了婚禮安寺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吞彤。我一直安慰自己我衬,他們只是感情好叹放,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挠羔,像睡著了一般井仰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上破加,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天俱恶,我揣著相機(jī)與錄音,去河邊找鬼范舀。 笑死合是,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锭环。 我是一名探鬼主播聪全,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼辅辩!你這毒婦竟也來了难礼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤玫锋,失蹤者是張志新(化名)和其女友劉穎蛾茉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撩鹿,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谦炬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了节沦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片键思。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖散劫,靈堂內(nèi)的尸體忽然破棺而出稚机,到底是詐尸還是另有隱情,我是刑警寧澤获搏,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站失乾,受9級特大地震影響常熙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碱茁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一裸卫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纽竣,春花似錦墓贿、人聲如沸茧泪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽队伟。三九已至,卻和暖如春幽勒,著一層夾襖步出監(jiān)牢的瞬間嗜侮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工啥容, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锈颗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓咪惠,卻偏偏與公主長得像击吱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子遥昧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • head first 設(shè)計模式渠鸽,是比較有趣的一本設(shè)計模式的書叫乌。 在學(xué)校里看書和在工作時看書,意義是不一樣的徽缚。在學(xué)校...
    DdShare閱讀 342評論 0 0
  • 設(shè)計模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計原則時需要注意以下幾點(diǎn):a) 高內(nèi)聚憨奸、低耦合和單一職能的“沖突”實(shí)際上,這兩者...
    彥幀閱讀 3,747評論 0 14
  • 學(xué)習(xí)設(shè)計模式不是一蹴而就的事情凿试,需要長時間的積累排宰,在平時寫代碼的時候多思考,學(xué)習(xí)設(shè)計模式的時候也不要死記硬背那婉,要了...
    tanghomvee閱讀 1,503評論 0 2
  • 接觸前端兩三個月的時候板甘,那時候只是聽說設(shè)計模式很重要,然后我就去讀了一本設(shè)計模式的書详炬,讀了一部分盐类,也不知道這些設(shè)計...
    艱苦奮斗的侯小憨閱讀 3,056評論 2 39
  • https://blog.csdn.net/u012124438/article/details/70039943...
    小陳阿飛閱讀 435評論 0 0