策略(Strategy)模式

策略模式是什么

策略模式的用意是針對(duì)一組算法烙丛,將每一個(gè)算法封裝到具有共同接口的獨(dú)立的類中跳纳,從而使得它們可以相互替換疟暖。策略模式使得算法可以在不影響到客戶端的情況下發(fā)生變化紊搪。
使用策略模式可以把行為和環(huán)境分割開來蜜葱。環(huán)境類負(fù)責(zé)維持和查詢行為類,各種算法則在具體策略類(ConcreteStrategy)中提供耀石。由于算法和環(huán)境獨(dú)立開來牵囤,算法的增減、修改都不會(huì)影響環(huán)境和客戶端。當(dāng)出現(xiàn)新的促銷折扣或現(xiàn)有的折扣政策出現(xiàn)變化時(shí)揭鳞,只需要實(shí)現(xiàn)新的策略類炕贵,并在客戶端登記即可。策略模式相當(dāng)于"可插入式(Pluggable)的算法"野崇。

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

策略模式是對(duì)算法的包裝称开,是把使用算法的責(zé)任和算法本身分割開,委派給不同的對(duì)象管理乓梨。策略模式通常把一個(gè)系列的算法包裝到一系列的策略類里面鳖轰,作為一個(gè)抽象策略類的子類。用一句話來說督禽,就是:"準(zhǔn)備一組算法脆霎,并將每一個(gè)算法封裝起來,使得它們可以互換狈惫。"


這個(gè)模式涉及到三個(gè)角色:

  • 環(huán)境(Context)角色:持有一個(gè)Strategy類的引用睛蛛。
  • 抽象策略(Strategy)角色:這是一個(gè)抽象角色,通常由一個(gè)接口或抽象類實(shí)現(xiàn)胧谈。此角色給出所有的具體策略類所需的接口忆肾。
  • 具體策略(ConcreteStrategy)角色:包裝了相關(guān)的算法或行為。

java示例代碼

import java.util.ArrayList;
import java.util.List;

public class StrategyPatternWiki {

    public static void main(final String[] arguments) {
        Customer firstCustomer = new Customer(new NormalStrategy());

        // Normal billing
        firstCustomer.add(1.0, 1);

        // Start Happy Hour
        firstCustomer.setStrategy(new HappyHourStrategy());
        firstCustomer.add(1.0, 2);

        // New Customer
        Customer secondCustomer = new Customer(new HappyHourStrategy());
        secondCustomer.add(0.8, 1);
        // The Customer pays
        firstCustomer.printBill();

        // End Happy Hour
        secondCustomer.setStrategy(new NormalStrategy());
        secondCustomer.add(1.3, 2);
        secondCustomer.add(2.5, 1);
        secondCustomer.printBill();
    }
}

class Customer {

    private List<Double> drinks;
    private BillingStrategy strategy;

    public Customer(final BillingStrategy strategy) {
        this.drinks = new ArrayList<Double>();
        this.strategy = strategy;
    }

    public void add(final double price, final int quantity) {
        drinks.add(strategy.getActPrice(price*quantity));
    }

    // Payment of bill
    public void printBill() {
        double sum = 0;
        for (Double i : drinks) {
            sum += i;
        }
        System.out.println("Total due: " + sum);
        drinks.clear();
    }

    // Set Strategy
    public void setStrategy(final BillingStrategy strategy) {
        this.strategy = strategy;
    }

}

interface BillingStrategy {
    double getActPrice(final double rawPrice);
}

// Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy {

    @Override
    public double getActPrice(final double rawPrice) {
        return rawPrice;
    }

}

// Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy {

    @Override
    public double getActPrice(final double rawPrice) {
        return rawPrice*0.5;
    }

}

策略模式的使用場景

在下面的情況下應(yīng)當(dāng)考慮使用策略模式:

  • 1菱肖、如果在一個(gè)系統(tǒng)里面有許多類客冈,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對(duì)象在許多行為中選擇一種行為稳强。

  • 2场仲、一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。那么這些算法可以包裝到一個(gè)個(gè)的具體算法類里面退疫,而這些具體算法類都是一個(gè)抽象算法類的子類渠缕。換言之,這些具體算法類均有統(tǒng)一的接口褒繁,由于多態(tài)性原則亦鳞,客戶端可以選擇使用任何一個(gè)具體算法類,并只持有一個(gè)數(shù)據(jù)類型是抽象算法類的對(duì)象棒坏。

  • 3燕差、一個(gè)系統(tǒng)的算法使用的數(shù)據(jù)不可以讓客戶端知道。策略模式可以避免讓客戶端涉及到不必要接觸到的復(fù)雜的和只與算法有關(guān)的數(shù)據(jù)坝冕。

  • 4徒探、如果一個(gè)對(duì)象有很多的行為,如果不用恰當(dāng)?shù)哪J轿箍撸@些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)刹帕。此時(shí)吵血,使用策略模式,把這些行為轉(zhuǎn)移到相應(yīng)的具體策略類里面偷溺,就可以避免使用難以維護(hù)的多重條件選擇語句,并體現(xiàn)面向?qū)ο笤O(shè)計(jì)的概念钱贯。

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

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

  • 1挫掏、 策略模式提供了管理相關(guān)的算法族的辦法。策略類的等級(jí)結(jié)構(gòu)定義了一個(gè)算法或行為族秩命。恰當(dāng)使用繼承可以把公共的代碼移到父類里面尉共,從而避免重復(fù)的代碼。

  • 2弃锐、策略模式提供了可以替換繼承關(guān)系的辦法袄友。繼承可以處理多種算法或行為。如果不是用策略模式霹菊,那么使用算法或行為的環(huán)境類就可能會(huì)有一些子類剧蚣,每一個(gè)子類提供一個(gè)不同的算法或行為。但是旋廷,這樣一來算法或行為的使用者就和算法或行為本身混在一起。決定使用哪一種算法或采取哪一種行為的邏輯就和算法或行為的邏輯混合在一起,從而不可能再獨(dú)立演化葫掉。繼承使得動(dòng)態(tài)改變算法或行為變得不可能拓哺。

  • 3、使用策略模式可以避免使用多重條件轉(zhuǎn)移語句扎运。多重轉(zhuǎn)移語句不易維護(hù)瑟曲,它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統(tǒng)統(tǒng)列在一個(gè)多重轉(zhuǎn)移語句里面豪治,比使用繼承的辦法還要原始和落后洞拨。

缺點(diǎn)有:

  • 1、客戶端必須知道所有的策略類鬼吵,并自行決定使用哪一個(gè)策略類扣甲。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴惓菀巍Q言之琉挖,策略模式只適用于客戶端知道所有的算法或行為的情況。

  • 2涣脚、策略模式造成很多的策略類示辈。有時(shí)候可以通過把依賴于環(huán)境的狀態(tài)保存到客戶端里面,而將策略類設(shè)計(jì)成可共享的遣蚀,這樣策略類實(shí)例可以被不同客戶端使用矾麻。換言之纱耻,可以使用享元模式來減少對(duì)象的數(shù)量。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末险耀,一起剝皮案震驚了整個(gè)濱河市弄喘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌甩牺,老刑警劉巖蘑志,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贬派,居然都是意外死亡急但,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門搞乏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來波桩,“玉大人,你說我怎么就攤上這事请敦「涠悖” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵冬三,是天一觀的道長匀油。 經(jīng)常有香客問我,道長勾笆,這世上最難降的妖魔是什么敌蚜? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮窝爪,結(jié)果婚禮上弛车,老公的妹妹穿的比我還像新娘。我一直安慰自己蒲每,他們只是感情好纷跛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邀杏,像睡著了一般贫奠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上望蜡,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天唤崭,我揣著相機(jī)與錄音,去河邊找鬼脖律。 笑死谢肾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的小泉。 我是一名探鬼主播芦疏,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冕杠,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了酸茴?” 一聲冷哼從身側(cè)響起分预,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薪捍,沒想到半個(gè)月后噪舀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡飘诗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了界逛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昆稿。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖息拜,靈堂內(nèi)的尸體忽然破棺而出溉潭,到底是詐尸還是另有隱情,我是刑警寧澤少欺,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布喳瓣,位于F島的核電站,受9級(jí)特大地震影響赞别,放射性物質(zhì)發(fā)生泄漏畏陕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一仿滔、第九天 我趴在偏房一處隱蔽的房頂上張望惠毁。 院中可真熱鬧,春花似錦崎页、人聲如沸鞠绰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜈膨。三九已至,卻和暖如春牺荠,著一層夾襖步出監(jiān)牢的瞬間翁巍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工志电, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留曙咽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓挑辆,卻偏偏與公主長得像例朱,于是被迫代替她去往敵國和親孝情。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理洒嗤,服務(wù)發(fā)現(xiàn)箫荡,斷路器,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 1 場景問題 1.1 報(bào)價(jià)管理 向客戶報(bào)價(jià)渔隶,對(duì)于銷售部門的人來講羔挡,這是一個(gè)非常重大、非常復(fù)雜的問題间唉,對(duì)不同的客戶要...
    4e70992f13e7閱讀 3,087評(píng)論 2 16
  • 設(shè)計(jì)模式匯總 一绞灼、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,947評(píng)論 1 15
  • 1 場景問題# 1.1 報(bào)價(jià)管理## 向客戶報(bào)價(jià)呈野,對(duì)于銷售部門的人來講低矮,這是一個(gè)非常重大、非常復(fù)雜的問題被冒,對(duì)不同的...
    七寸知架構(gòu)閱讀 5,080評(píng)論 9 62
  • 「原文鏈接」 如果你是正則表達(dá)式新人(至少當(dāng)它們用于 Perl 6 中時(shí)), 那我建議你從這個(gè)系列的第一部分開始军掂。...
    焉知非魚閱讀 512評(píng)論 0 2