策略模式--避免冗長的if/else

算是讀書筆記吧

極客時間--設(shè)計(jì)模式之美


什么是策略模式

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
定義一族算法類春寿,將每個算法分別封裝起來颅停,讓它們可以互相替換僚祷。策略模式可以使算法的變化獨(dú)立于使用它們的客戶端(這里的客戶端代指使用算法的代碼)

策略模式對策略的定義宁脊、創(chuàng)建、使用三部分進(jìn)行了解耦


策略模式的作用

策略模式解決的問題

策略模式表面上看是為了避免 if-else 分支判斷邏輯,但更深層次上,還是為了解耦以及控制代碼復(fù)雜度

比如在出門旅游時:路線、交通工具的類型溢吻、天數(shù)、艙位等級果元、餐飲促王、住宿等等。
每個節(jié)點(diǎn)在執(zhí)行時而晒,都需要根據(jù)預(yù)算Type進(jìn)行不同的操作蝇狼,從而引起大量的if-else判斷。增加一個策略欣硼,修改一個策略题翰,都有可能牽一發(fā)而動全身。需要對所有狀態(tài)進(jìn)行回測诈胜。

public void departure () {
  Int money = 100;
  String destination = getDestination(money); //獲取目的地
  String vehicles = getVehicles(money); //獲取交通工具
  天數(shù)豹障、艙位等級、餐飲焦匈、住宿等等.....
}

private String getDestination (Int money) {
  if (num < 1000) {
    return "1000塊能去得起的地方";
  } else if (num < 5000) {
    return "5000塊能去得起的地方";
  } else if (num < 10000) {
    return "10000塊能去得起的地方";
  } else if (num < 20000) {
    return "20000塊能去得起的地方";
  } else if (num < 40000) {
    return "40000塊能去得起的地方";
  } else if (num < 80000) {
    return "80000塊能去得起的地方";
  } else  ...
}

private String getVehicles (Int money) {
  if (num < 1000) {
    return "騎車";
  } else if (num < 5000) {
    return "火車";
  } else if (num < 10000) {
    return "火車";
  } else if (num < 20000) {
    return "飛機(jī)";
  } else if (num < 40000) {
    return "飛機(jī)";
  } else if (num < 80000) {
    return "飛機(jī)";
  } else  ...
}

...后面還有一大堆相關(guān)的方法需要判斷

整個業(yè)務(wù)如圖所示血公,所有的判斷都耦合在業(yè)務(wù)流程內(nèi)部,牽一發(fā)而動全身

使用策略模式

我們可以將某一條件(Type)下的邏輯缓熟,聚合封裝到具體的策略類中

public class departureStrategy1000 implements Strategy {  //1000塊的旅行策略
  @Override
  public void  getDestination() {
    return "1000塊能去得起的地方";
  }
  public void  getVehicles() {
    return "騎車";
  }
  天數(shù)累魔、艙位等級、餐飲够滑、住宿等等.....
}

使用策略類后如圖所示垦写,每個的情況被封裝聚合到單個策略類中,相互隔離


所以策略模式的作用主要體現(xiàn)在:

  1. 解耦策略的定義彰触、創(chuàng)建和使用
    控制代碼的復(fù)雜度梯投,讓每個部分都不至于過于復(fù)雜、代碼量過多况毅。
  2. 讓復(fù)雜框架滿足開閉原則
    添加或者修改新策略的時候分蓖,最小化、集中化代碼改動尔许,減少引入 bug 的風(fēng)險么鹤。

策略的定義

策略的定義包含一個策略接口和一組實(shí)現(xiàn)這個接口的策略類。
利用基于接口而非實(shí)現(xiàn)編程的方式味廊,對具體策略進(jìn)行解耦蒸甜。

如下棠耕,策略類ConcreteStrategyA、ConcreteStrategyB在策略接口algorithmInterface的使用上柠新,可以隨意替換昧辽。

public interface Strategy {  //定義策略接口
  void algorithmInterface();
}

public class ConcreteStrategyA implements Strategy {  //實(shí)現(xiàn)策略接口的策略類A
  @Override
  public void  algorithmInterface() {
    //具體的算法...
  }
}

public class ConcreteStrategyB implements Strategy { //實(shí)現(xiàn)策略接口的策略類B
  @Override
  public void  algorithmInterface() {
    //具體的算法...
  }
}

策略的創(chuàng)建

通常會通過類型(type)來判斷創(chuàng)建哪個策略來使用。

這里登颓,有兩種創(chuàng)建方式

if-else創(chuàng)建

適用有狀態(tài)的策略類,每次創(chuàng)建一個新的策略類給業(yè)務(wù)方使用


public class StrategyFactory {
  public static Strategy getStrategy(String type) {
    if (type == null || type.isEmpty()) {
      throw new IllegalArgumentException("type should not be empty.");
    }

    if (type.equals("A")) {
      return new ConcreteStrategyA();
    } else if (type.equals("B")) {
      return new ConcreteStrategyB();
    }

    return null;
  }
}

通過工廠模式里的Map進(jìn)行創(chuàng)建

適用于無狀態(tài)的策略類創(chuàng)建红氯,大家共用一個策略類即可

public class StrategyFactory {
  private static final Map<String, Strategy> strategies = new HashMap<>();

  static {
    strategies.put("A", new ConcreteStrategyA());
    strategies.put("B", new ConcreteStrategyB());
  }

  public static Strategy getStrategy(String type) {
    if (type == null || type.isEmpty()) {
      throw new IllegalArgumentException("type should not be empty.");
    }
    return strategies.get(type);
  }
}

本質(zhì)上點(diǎn)講框咙,是借助“查表法”,根據(jù) type 查表替代根據(jù) type 分支判斷痢甘。

有狀態(tài)的策略類如何用Map進(jìn)行創(chuàng)建

可以利用閉包的特性喇嘱,將創(chuàng)建的邏輯封裝進(jìn)callback中,然后將callback存進(jìn)Map


策略類的使用

如果使用工廠方法創(chuàng)建策略類塞栅,其實(shí)就和工廠方法相同者铜。
只不過我們從工廠取出來的不再是一個某一個具體類的子類簇。
而是一個實(shí)現(xiàn)了策略接口的類簇放椰。

// 運(yùn)行時動態(tài)確定作烟,根據(jù)配置文件的配置決定使用哪種策略
public class Application {
  public static void main(String[] args) throws Exception {
    Strategy strategy = null;
    StrategyFactory factory = new StrategyFactory(); 
    strategy = factory.getStrategy("A"); //獲取策略類
    strategy.algorithmInterface(); //調(diào)用策略接口
    //...
  }
}

是不是要抹殺所有的if/else

如果 if-else 分支判斷不復(fù)雜、代碼不多砾医,這并沒有任何問題拿撩,畢竟 if-else 分支判斷幾乎是所有編程語言都會提供的語法,存在即有理由如蚜。遵循 KISS 原則压恒,怎么簡單怎么來,就是最好的設(shè)計(jì)错邦。非得用策略模式探赫,搞出 n 多類,反倒是一種過度設(shè)計(jì)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撬呢,一起剝皮案震驚了整個濱河市伦吠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌倾芝,老刑警劉巖讨勤,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晨另,居然都是意外死亡潭千,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門借尿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刨晴,“玉大人屉来,你說我怎么就攤上這事”否” “怎么了茄靠?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝶桶。 經(jīng)常有香客問我慨绳,道長,這世上最難降的妖魔是什么真竖? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任脐雪,我火速辦了婚禮,結(jié)果婚禮上恢共,老公的妹妹穿的比我還像新娘战秋。我一直安慰自己,他們只是感情好讨韭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布脂信。 她就那樣靜靜地躺著,像睡著了一般透硝。 火紅的嫁衣襯著肌膚如雪狰闪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天蹬铺,我揣著相機(jī)與錄音尝哆,去河邊找鬼。 笑死甜攀,一個胖子當(dāng)著我的面吹牛秋泄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播规阀,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼恒序,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谁撼?” 一聲冷哼從身側(cè)響起歧胁,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厉碟,沒想到半個月后喊巍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡箍鼓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年崭参,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片款咖。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡何暮,死狀恐怖奄喂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情海洼,我是刑警寧澤跨新,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站坏逢,受9級特大地震影響域帐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜是整,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一俯树、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贰盗,春花似錦、人聲如沸阳欲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽球化。三九已至秽晚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筒愚,已是汗流浹背赴蝇。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巢掺,地道東北人句伶。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像陆淀,于是被迫代替她去往敵國和親考余。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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