設(shè)計(jì)模式-策略模式(一)

序言

??都畢業(yè)好幾年了,對(duì)于設(shè)計(jì)模式剖效,平時(shí)也偶爾接觸過嫉入,但卻沒有系統(tǒng)的學(xué)習(xí)過,自然在遇到問題找解決方案的時(shí)候璧尸,也很少能想到設(shè)計(jì)模式咒林,感覺總是一種模糊的狀態(tài),所以爷光,準(zhǔn)備重寫梳理一下垫竞。

注:本系列設(shè)計(jì)模式相關(guān)代碼,開發(fā)語言使用Java蛀序,JDK版本基于1.8件甥。

概述

??策略模式是屬于一種行為型的設(shè)計(jì)模式,針對(duì)的是算法哼拔。我們可以通俗的理解為,策略模式就是對(duì)某一行為瓣颅,能根據(jù)不同的實(shí)現(xiàn)倦逐,完成相同的功能。比如排序宫补,我們能根據(jù)不同的類型檬姥,調(diào)用不同的實(shí)現(xiàn),來實(shí)現(xiàn)相同的功能粉怕,就是排序健民。

實(shí)現(xiàn)

策略模式中涉及到三個(gè)角色:

  1. Context角色:持有一個(gè)Strategy角色的引用;
  2. Strategy(抽象策略)角色:該角色通常是接口或抽象類贫贝;
  3. ConcreteStrategy(具體策略)角色:實(shí)現(xiàn)了抽象策略角色的算法秉犹。
策略模式.png

實(shí)例

??我們拿一個(gè)例子來加深對(duì)策略模式的了解。比如大家出去旅游稚晚,可以選擇開火車崇堵,也可以選擇騎自行車,也可以選擇做汽車客燕。這其實(shí)就是一種策略模式的應(yīng)用鸳劳。

Strategy角色
public interface Strategy {
    void travel();
}

抽象角色,只有一個(gè)方法也搓,就是出行的方法赏廓。

ConcreteStrategy具體策略

選擇坐汽車出去玩:

public class CarStrategy implements Strategy{
    @Override
    public void travel() {
        System.out.println("--做汽車出去玩--");
    }
}

選擇騎自行車出去玩:

public class BikeStrategy implements Strategy{
    @Override
    public void travel() {
        System.out.println("--騎自行車出去玩--");
    }
}

選擇坐火車出去玩:

public class TrainStrategy implements Strategy{
    @Override
    public void travel() {
        System.out.println("--坐火車出去玩--");
    }
}
Context角色

出去玩的對(duì)象是人:

public class PersonContext {
    private Strategy strategy;

    public PersonContext(Strategy strategy) {
        this.strategy = strategy;
    }

    public void travel() {
        strategy.travel();
    }
}
ClientTest
public class ClientTest {
    public static void main(String[] args) {
        PersonContext personContext = new PersonContext(new BikeStrategy());
        personContext.travel();

        personContext = new PersonContext(new TrainStrategy());
        personContext.travel();
    }
}

打印結(jié)果:

--騎自行車出去玩--
--坐火車出去玩--

??這時(shí)候如果說涵紊,這時(shí)候出行的方式要改為坐輪船,其實(shí)這就相當(dāng)于更改策略幔摸,那我們?cè)賹?shí)現(xiàn)一個(gè)類摸柄,然后再調(diào)用的時(shí)候想辦法把參數(shù)傳進(jìn)去就可以了。
??有一點(diǎn)抚太,這里使用構(gòu)造方法傳參數(shù)并不是必須的塘幅,當(dāng)然我們可以通過其他方式傳遞參數(shù),只需要把參數(shù)傳遞過去即可尿贫。

其實(shí)從上面代碼中我們可以分析得到:

  1. 策略模式就是對(duì)于同一行為(出行)电媳,通過不同的實(shí)現(xiàn)(汽車,火車庆亡,自行車)匾乓,達(dá)到相同的目的。
  2. 策略模式的側(cè)重點(diǎn)就是在行為上又谋,所以要對(duì)行為進(jìn)行抽象拼缝,所以很適合用接口來表示。
  3. 很多時(shí)候彰亥,策略的實(shí)現(xiàn)可以通過匿名內(nèi)部類或者Lambda表達(dá)式的形式來實(shí)現(xiàn)咧七,比如Collections的sort方法;

??既然說道了Collections的sort方法任斋,我們?cè)僖訡ollections的sort方法來舉一個(gè)例子继阻,比如我們要對(duì)自定義對(duì)象進(jìn)行排序:
自定義對(duì)象Person,我們要根據(jù)其中的屬性進(jìn)行排序:

public class Person {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
}

自定義比較器PersonComparator:

public class PersonComparator implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
}

進(jìn)行測(cè)試:

public class ComparatorTest {
    public static void main(String[] args) {
        List<Person> list = getPersonList();
        Collections.sort(list, new PersonComparator());
        System.out.println(list);
    }

    public static List<Person> getPersonList() {
        Person person1 = new Person();
        person1.setAge(10);
        Person person2 = new Person();
        person2.setAge(15);
        Person person3 = new Person();
        person3.setAge(12);
        List<Person> list = new ArrayList<>();
        list.add(person1);
        list.add(person2);
        list.add(person3);
        return list;
    }
}

打印結(jié)果:

[Person{age=10}, Person{age=12}, Person{age=15}]

當(dāng)然废酷,這種情況我們也可以使用匿名類來實(shí)現(xiàn)該功能:

public static void main(String[] args) {
        List<Person> list = getPersonList();
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        System.out.println(list);
    }

然后我們也可以使用Lambda表達(dá)式來實(shí)現(xiàn):

Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());

再然后瘟檩,我們還可以使用JDK8中中Comparator里的comparingInt來實(shí)現(xiàn):

Collections.sort(list, Comparator.comparingInt(Person::getAge));

從上面就可以看出來,Collections.sort方法就是策略模式的一種很好的詮釋澈蟆。這里的Comparator就相當(dāng)于Strategy角色墨辛,而Collections則具備了Context的角色。

總結(jié)

  1. 策略模式趴俘,就是對(duì)于同一行為睹簇,通過不同的實(shí)現(xiàn),完成相同的功能哮幢。策略模式封裝的是一種變化的狀態(tài)带膀。所以說當(dāng)我們有類似的,需要針對(duì)不同的情況實(shí)現(xiàn)不同的規(guī)則的時(shí)候橙垢,不妨考慮使用下策略模式垛叨。
  2. 很多時(shí)候策略類可以使用匿名類或JDK8之后的Lambda表達(dá)式來實(shí)現(xiàn),從而避免實(shí)現(xiàn)太多的類;
  3. 使用策略模式的時(shí)候還會(huì)有一個(gè)問題,因?yàn)椴呗阅J街兴惴ǖ倪x擇是由客戶端決定的,所以策略模式在使用的時(shí)候客戶端必須要知道所有的策略類樱衷,明白不同的策略類處理哪些不同的功能啦逆。然后根據(jù)需要決定使用哪一個(gè)策略類评疗。

本文參考自:
深入理解Arrays.sort()
策略設(shè)計(jì)模式使用
《大話設(shè)計(jì)模式》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旁壮,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谐檀,死亡現(xiàn)場(chǎng)離奇詭異抡谐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)桐猬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門麦撵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溃肪,你說我怎么就攤上這事免胃。” “怎么了惫撰?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵羔沙,是天一觀的道長。 經(jīng)常有香客問我厨钻,道長撬碟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任莉撇,我火速辦了婚禮,結(jié)果婚禮上惶傻,老公的妹妹穿的比我還像新娘棍郎。我一直安慰自己,他們只是感情好银室,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布涂佃。 她就那樣靜靜地躺著,像睡著了一般蜈敢。 火紅的嫁衣襯著肌膚如雪辜荠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天抓狭,我揣著相機(jī)與錄音伯病,去河邊找鬼。 笑死否过,一個(gè)胖子當(dāng)著我的面吹牛午笛,可吹牛的內(nèi)容都是我干的惭蟋。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼药磺,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼告组!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起癌佩,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤木缝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后围辙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體我碟,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年酌畜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怎囚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桥胞,死狀恐怖恳守,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贩虾,我是刑警寧澤催烘,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站缎罢,受9級(jí)特大地震影響伊群,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜策精,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一舰始、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咽袜,春花似錦丸卷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至凹联,卻和暖如春沐兰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔽挠。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來泰國打工住闯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓寞秃,卻偏偏與公主長得像斟叼,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子春寿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

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

  • 一直想把常見的設(shè)計(jì)模式系統(tǒng)地學(xué)習(xí)一遍朗涩,結(jié)果和大多數(shù)人一樣,過了幾天就沒能堅(jiān)持下去了绑改。我發(fā)現(xiàn)學(xué)習(xí)這件事情急不得谢床,往往...
    Neulana閱讀 563評(píng)論 5 2
  • 前言 設(shè)計(jì)模式是我們實(shí)際應(yīng)用開發(fā)中必不可缺的,對(duì)設(shè)計(jì)模式的理解有助于我們寫出可讀性和擴(kuò)展更高的應(yīng)用程序厘线。雖然設(shè)計(jì)模...
    丶legend閱讀 533評(píng)論 0 3
  • 思考: 假設(shè)有個(gè)需求识腿,模擬鴨子游戲:在游戲中會(huì)出現(xiàn)各種各樣的鴨子,一邊游泳戲水造壮,一邊呱呱叫渡讼。開始我們的設(shè)計(jì)吧: 這...
    MarksGui閱讀 180評(píng)論 0 0
  • “夏明秀死了,前幾天在醫(yī)院死了耳璧〕审铮”姐姐回家后一臉倦容的說道。 其實(shí)論起輩分來旨枯,我是夏老太的干孫女蹬昌,...
    宮長青箏閱讀 149評(píng)論 0 0
  • 程專欄連載的練手項(xiàng)目篇,如有興趣可以訪問前三篇: 有哪些適合新手練手的Java項(xiàng)目攀隔? - 學(xué)習(xí)編程 - 知乎專欄 ...
    達(dá)魔學(xué)院閱讀 438評(píng)論 0 2