策略模式

簡(jiǎn)介

Define a family of algorithms,encapsulate each one,and make them interchangeable.
定義一組算法蹬挺,將每個(gè)算法都封裝起來(lái)唬滑,并且使它們之間可以互換域携。

策略模式(Strategy Pattern) 也叫 政策模式(Policy Pattern)鱼喉。指的是對(duì)象具備某個(gè)行為,但是在不同的場(chǎng)景中扛禽,該行為有不同的實(shí)現(xiàn)算法锋边。比如一個(gè)人的交稅比率與他的工資有關(guān),不同的工資水平對(duì)應(yīng)不同的稅率编曼。

策略模式 使用的就是面向?qū)ο蟮睦^承和多態(tài)機(jī)制豆巨,從而實(shí)現(xiàn)同一行為在不同場(chǎng)景下具備不同實(shí)現(xiàn)。

策略模式 本質(zhì):分離算法掐场,選擇實(shí)現(xiàn)

主要解決

在有多種算法相似的情況下往扔,使用 if...else 或 switch...case 所帶來(lái)的復(fù)雜性和臃腫性。

優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 算法多樣性熊户,且具備自由切換功能萍膛;
  • 有效避免多重條件判斷,增強(qiáng)了封裝性嚷堡,簡(jiǎn)化了操作卦羡,降低出錯(cuò)概率;
  • 擴(kuò)展性良好麦到,策略類遵頊 里氏替換原則绿饵,可以很方便地進(jìn)行策略擴(kuò)展;

缺點(diǎn)

  • 策略類數(shù)量增多瓶颠,且所有策略類都必須對(duì)外暴露拟赊,以便客戶端能進(jìn)行選擇;

使用場(chǎng)景

  • 針對(duì)同一類型問(wèn)題粹淋,有多種處理方式吸祟,每一種都能獨(dú)立解決問(wèn)題瑟慈;
  • 算法需要自由切換的場(chǎng)景;
  • 需要屏蔽算法規(guī)則的場(chǎng)景屋匕;

模式講解

首先來(lái)看下 策略模式 的通用 UML 類圖:

策略模式

從 UML 類圖中葛碧,我們可以看到,策略模式 主要包含三種角色:

  • 上下文角色(Context):用來(lái)操作策略的上下文環(huán)境过吻,屏蔽高層模塊(客戶端)對(duì)策略进泼,算法的直接訪問(wèn),封裝可能存在的變化纤虽;
  • 抽象策略角色(Strategy):規(guī)定策略或算法的行為乳绕;
  • 具體策略角色(ConcreteStrategy):具體的策略或算法實(shí)現(xiàn);

以下是 策略模式 的通用代碼:

class Client {
    public static void main(String[] args) {
        //選擇一個(gè)具體策略
        IStrategy strategy = new ConcreteStrategyA();
        //來(lái)一個(gè)上下文環(huán)境
        Context context = new Context(strategy);
        //客戶端直接讓上下文環(huán)境執(zhí)行算法
        context.algorithm();
    }

    //抽象策略類 Strategy
    interface IStrategy {
        void algorithm();
    }

    //具體策略類 ConcreteStrategy
    static class ConcreteStrategyA implements IStrategy {

        @Override
        public void algorithm() {
            System.out.println("Strategy A");
        }
    }

    //具體策略類 ConcreteStrategy
    static class ConcreteStrategyB implements IStrategy {

        @Override
        public void algorithm() {
            System.out.println("Strategy B");
        }
    }

    //上下文環(huán)境
    static class Context {
        private IStrategy mStrategy;

        public Context(IStrategy strategy) {
            this.mStrategy = strategy;
        }

        public void algorithm() {
            this.mStrategy.algorithm();
        }
    }
}

舉個(gè)例子

例子:假設(shè)現(xiàn)在有兩個(gè)數(shù)與一個(gè)運(yùn)算符逼纸,要求使用該運(yùn)算符操作這兩個(gè)數(shù)洋措。
分析:直接思路:通過(guò)判斷運(yùn)算符符號(hào),對(duì)這兩個(gè)數(shù)進(jìn)行運(yùn)算杰刽。代碼如下所示:

    static class Calculator {
        private static final String SYMBOL_ADD = "+";
        private static final String SYMBOL_SUB = "-";

        public int calc(int a, int b, final String symbol) {
            int result = 0;
            if (SYMBOL_ADD.equals(symbol)) {
                result = a + b;
            } else if (SYMBOL_SUB.equals(symbol)) {
                result = a - b;
            }
            return result;
        }
    }

但是這樣寫的話菠发,如果我們現(xiàn)在要擴(kuò)展乘法*或除法/運(yùn)算,那么就要在calc方法內(nèi)增加對(duì)應(yīng)的if...else判斷贺嫂,代碼臃腫并且擴(kuò)展性太低雷酪。
而如果采用策略模式涝婉,將各種運(yùn)算符的計(jì)算都?xì)w并到對(duì)應(yīng)具體策略,這樣吩跋,就能簡(jiǎn)化代碼并且?guī)?lái)很好的擴(kuò)展性渔工,具體代碼如下:

class Client {
    public static void main(String[] args) {
        ICalculator calculator = new Add();
        Context context = new Context(calculator);
        int result = context.calc(1,2);
        System.out.println(result);
    }

    interface ICalculator {
        int calc(int a, int b);
    }

    static class Add implements ICalculator {
        @Override
        public int calc(int a, int b) {
            return a + b;
        }
    }

    static class Sub implements ICalculator {
        @Override
        public int calc(int a, int b) {
            return a - b;
        }
    }

    static class Multi implements ICalculator {
        @Override
        public int calc(int a, int b) {
            return a * b;
        }
    }

    static class Divide implements ICalculator {
        @Override
        public int calc(int a, int b) {
            return a / b;
        }
    }

    static class Context {
        private ICalculator mCalculator;

        public Context(ICalculator calculator) {
            this.mCalculator = calculator;
        }

        public int calc(int a, int b) {
            return this.mCalculator.calc(a, b);
        }
    }
}

從上面代碼中梁丘,我們可以看到旺韭,我們完全消除了對(duì)運(yùn)算符號(hào)進(jìn)行判斷的哪些if...else的冗余代碼区端,取而代之的是客戶端直接決定使用哪種算法,然后交由上下文獲取結(jié)果杨何。并且上面代碼中我們還擴(kuò)展了乘法Multi和除法Divide運(yùn)算,所需要做的就只是擴(kuò)展相應(yīng)的策略類而已危虱。

注意策略模式 中的上下文環(huán)境(Context)埃跷,其職責(zé)本來(lái)是隔離客戶端與策略類的耦合,讓客戶端完全與上下文環(huán)境溝通,無(wú)需關(guān)系具體策略近弟。但是從上面的代碼中我們可以看到祷愉,客戶端內(nèi)部直接自己指定要哪種策略(ICalculator calculator = new Add()),客戶端與具體策略類耦合了赴涵,而上下文環(huán)境在這里其的作用只是負(fù)責(zé)調(diào)度執(zhí)行订讼,獲取結(jié)果,并沒(méi)有完全起到隔離客戶端與策略類的作用寄纵。一般可以通過(guò)簡(jiǎn)單工廠模式將具體策略的創(chuàng)建與客戶端進(jìn)行隔離程拭,或者是通過(guò) 策略枚舉 將上下文環(huán)境與具體策略類融合在一起棍潘,簡(jiǎn)化代碼。當(dāng)具體策略相對(duì)穩(wěn)定時(shí)恤浪,推薦使用 策略枚舉 簡(jiǎn)化代碼资锰,具體代碼如下:

class EnumClient {
    public static void main(String[] args) {
        int result = Calculator.ADD.calc(1, 2);
        System.out.println(result);
        // System.out.println(Calculator.ADD.getSymbol());
    }

    static enum Calculator {
        // 加法運(yùn)算
        ADD("+") {
            @Override
            public int calc(int a, int b) {
                return a + b;
            }
        },
        SUB("-") {
            @Override
            public int calc(int a, int b) {
                return a - b;
            }
        };
        private String symbol;

        private Calculator(String symbol) {
            this.symbol = symbol;
        }

        public String getSymbol() {
            return this.symbol;
        }

        public abstract int calc(int a, int b);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绷杜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子圾结,更是在濱河造成了極大的恐慌齿诉,老刑警劉巖粤剧,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抵恋,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盅安,警方通過(guò)查閱死者的電腦和手機(jī)世囊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門株憾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人籽慢,你說(shuō)我怎么就攤上這事箱亿∑眩” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵脑豹,是天一觀的道長(zhǎng)衡查。 經(jīng)常有香客問(wèn)我,道長(zhǎng)俱饿,這世上最難降的妖魔是什么拍埠? 我笑而不...
    開(kāi)封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮嬉探,結(jié)果婚禮上棉圈,老公的妹妹穿的比我還像新娘。我一直安慰自己胎围,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布垮抗。 她就那樣靜靜地躺著,像睡著了一般冒版。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捆等,一...
    開(kāi)封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天续室,我揣著相機(jī)與錄音挺狰,去河邊找鬼。 笑死薯定,一個(gè)胖子當(dāng)著我的面吹牛瞳购,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吞杭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼篇亭!你這毒婦竟也來(lái)了译蒂?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柔昼,失蹤者是張志新(化名)和其女友劉穎捕透,沒(méi)想到半個(gè)月后碴萧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虎谢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年婴噩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了几莽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宅静。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖纤垂,靈堂內(nèi)的尸體忽然破棺而出洒忧,到底是詐尸還是另有隱情够颠,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布蛉抓,位于F島的核電站,受9級(jí)特大地震影響驶忌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜付魔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一飞蹂、第九天 我趴在偏房一處隱蔽的房頂上張望陈哑。 院中可真熱鬧,春花似錦惊窖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赁遗。三九已至岩四,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間材鹦,已是汗流浹背耕姊。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尤泽,地道東北人坯约。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像横殴,于是被迫代替她去往敵國(guó)和親卿拴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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

  • 2017年10月5日 多云 曬滿衣服的陽(yáng)臺(tái) 飄一點(diǎn)水花的地板 干凈的頭發(fā) 茉莉香的手掌紋 耗盡了漫天的時(shí)間 我打發(fā)...
    鮮栗子閱讀 228評(píng)論 0 2
  • 什么是人最好的狀態(tài)到踏? 不是過(guò)了這一陣子,就好了楣富,還有一下陣子伴榔。而是只有過(guò)好這一陣子,下一陣子才會(huì)更加精彩~
    1a56d72b3359閱讀 287評(píng)論 0 0
  • 第一次在電視劇《古劍奇譚》里面塘安,看到她的時(shí)候兼犯,覺(jué)得這個(gè)妹子的眼睛,怎么可以這么明亮有神切黔,就像動(dòng)畫片里面的一樣具篇。 第...
    晨光花開(kāi)閱讀 285評(píng)論 0 1