<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          解鎖新姿勢(shì):探討復(fù)雜的?if-else?語句“優(yōu)雅處理”的思路

          共 4858字,需瀏覽 10分鐘

           ·

          2020-02-23 23:20


          作者丨h(huán)yzhan43

          來源:

          juejin.im/post/5def654f51882512302daeef

          前言

          在之前文章說到,簡(jiǎn)單 if-else,可以使用 衛(wèi)語句 進(jìn)行優(yōu)化。但是在實(shí)際開發(fā)中,往往不是簡(jiǎn)單 if-else 結(jié)構(gòu),我們通常會(huì)不經(jīng)意間寫下如下代碼:
          --------------------?理想中的?if-else??--------------------
          public?void?today()?{
          ????if?(isWeekend())?{
          ????????System.out.println("玩游戲");
          ????}?else?{
          ????????System.out.println("上班!");
          ????}
          }


          --------------------?現(xiàn)實(shí)中的?if-else??--------------------

          if?(money?>=?1000)?{
          ????if?(type?==?UserType.SILVER_VIP.getCode())?{

          ????????System.out.println("白銀會(huì)員?優(yōu)惠50元");
          ????????result?=?money?-?50;
          ????}?else?if?(type?==?UserType.GOLD_VIP.getCode())?{

          ????????System.out.println("黃金會(huì)員?8折");
          ????????result?=?money?*?0.8;
          ????}?else?if?(type?==?UserType.PLATINUM_VIP.getCode())?{

          ????????System.out.println("白金會(huì)員?優(yōu)惠50元,再打7折");
          ????????result?=?(money?-?50)?*?0.7;
          ????}?else?{
          ????????System.out.println("普通會(huì)員?不打折");
          ????????result?=?money;
          ????}
          }


          //省略?n?個(gè)?if-else?......
          毫不夸張的說,我們都寫過類似的代碼,回想起被 if-else 支配的恐懼,我們常常無所下手,甚至不了了之。下面分享一下我在開發(fā)中遇到復(fù)雜的 if-else 語句“優(yōu)雅處理”思路。如有不妥,歡迎大家一起交流學(xué)習(xí)。

          需求

          假設(shè)有這么一個(gè)需求:一個(gè)電商系統(tǒng),當(dāng)用戶消費(fèi)滿1000 金額,可以根據(jù)用戶VIP等級(jí),享受打折優(yōu)惠。
          根據(jù)用戶VIP等級(jí),計(jì)算出用戶最終的費(fèi)用。
          • 普通會(huì)員 不打折
          • 白銀會(huì)員 優(yōu)惠50元
          • 黃金會(huì)員 8折
          • 白金會(huì)員 優(yōu)惠50元,再打7折

          編碼實(shí)現(xiàn)

          private?static?double?getResult(long?money,?int?type)?{

          ????double?result?=?money;

          ????if?(money?>=?1000)?{
          ????????if?(type?==?UserType.SILVER_VIP.getCode())?{

          ????????????System.out.println("白銀會(huì)員?優(yōu)惠50元");
          ????????????result?=?money?-?50;
          ????????}?else?if?(type?==?UserType.GOLD_VIP.getCode())?{

          ????????????System.out.println("黃金會(huì)員?8折");
          ????????????result?=?money?*?0.8;
          ????????}?else?if?(type?==?UserType.PLATINUM_VIP.getCode())?{

          ????????????System.out.println("白金會(huì)員?優(yōu)惠50元,再打7折");
          ????????????result?=?(money?-?50)?*?0.7;
          ????????}?else?{
          ????????????System.out.println("普通會(huì)員?不打折");
          ????????????result?=?money;
          ????????}
          ????}

          ????return?result;
          }
          為了方便演示,代碼上我進(jìn)行了簡(jiǎn)單實(shí)現(xiàn),但實(shí)際上 if - else 會(huì)進(jìn)行復(fù)雜的邏輯計(jì)費(fèi)。從功能上來說,基本完成,但是對(duì)于我這種有代碼潔癖的人來說,代碼質(zhì)量上不忍直視。我們開始著手 優(yōu)化一下我們的第一版代碼吧。

          思考

          看到如上代碼,聰明的朋友首先想到的是,這不是典型的策略模式嗎?你可真是個(gè)機(jī)靈鬼,我們先嘗試用策略模式來優(yōu)化一下代碼吧。

          策略模式

          什么是策略模式?

          可能有的朋友還不清楚,什么是策略模式。策略模式是定義一系列的算法,把它們一個(gè)個(gè)封裝起來, 并且使它們可相互替換。比如上述需求,有返利、有打折、有折上折等等。這些算法本身就是一種策略。并且這些算法可以相互替換的,比如今天我想讓 白銀會(huì)員優(yōu)惠50,明天可以替換為 白銀會(huì)員打9折。說了那么多,不如編碼來得實(shí)在。

          編碼

          public?interface?Strategy?{

          ????//?計(jì)費(fèi)方法
          ????double?compute(long?money);
          }

          //?普通會(huì)員策略
          public?class?OrdinaryStrategy?implements?Strategy?{

          ????@Override
          ????public?double?compute(long?money)?{
          ????????System.out.println("普通會(huì)員?不打折");
          ????????return?money;
          ????}
          }

          //?白銀會(huì)員策略
          public?class?SilverStrategy?implements?Strategy?{

          ????@Override
          ????public?double?compute(long?money)?{

          ????????System.out.println("白銀會(huì)員?優(yōu)惠50元");
          ????????return?money?-?50;
          ????}
          }

          //?黃金會(huì)員策略
          public?class?GoldStrategy?implements?Strategy{

          ????@Override
          ????public?double?compute(long?money)?{
          ????????System.out.println("黃金會(huì)員?8折");
          ????????return?money?*?0.8;
          ????}
          }

          //?白金會(huì)員策略
          public?class?PlatinumStrategy?implements?Strategy?{
          ????@Override
          ????public?double?compute(long?money)?{
          ????????System.out.println("白金會(huì)員?優(yōu)惠50元,再打7折");
          ????????return?(money?-?50)?*?0.7;
          ????}
          }
          我們定義來一個(gè) Strategy 接口,并且定義 四個(gè)子類,實(shí)現(xiàn)接口。在對(duì)應(yīng)的 compute方法 實(shí)現(xiàn)自身策略的計(jì)費(fèi)邏輯。
          private?static?double?getResult(long?money,?int?type)?{

          ????double?result?=?money;

          ????if?(money?>=?1000)?{
          ????????if?(type?==?UserType.SILVER_VIP.getCode())?{

          ????????????result?=?new?SilverStrategy().compute(money);
          ????????}?else?if?(type?==?UserType.GOLD_VIP.getCode())?{

          ????????????result?=?new?GoldStrategy().compute(money);
          ????????}?else?if?(type?==?UserType.PLATINUM_VIP.getCode())?{

          ????????????result?=?new?PlatinumStrategy().compute(money);
          ????????}?else?{
          ????????????result?=?new?OrdinaryStrategy().compute(money);
          ????????}
          ????}

          ????return?result;
          }
          然后對(duì)應(yīng) getResult 方法,根據(jù) type 替換為對(duì)應(yīng)的 用戶VIP 策略。這里代碼上出現(xiàn)了重復(fù)的調(diào)用 compute ,我們可以嘗試進(jìn)一步優(yōu)化。
          private?static?double?getResult(long?money,?int?type)?{

          ????if?(money?1000
          )?{
          ????????return?money;
          ????}

          ????Strategy?strategy;

          ????if?(type?==?UserType.SILVER_VIP.getCode())?{
          ????????strategy?=?new?SilverStrategy();
          ????}?else?if?(type?==?UserType.GOLD_VIP.getCode())?{
          ????????strategy?=?new?GoldStrategy();
          ????}?else?if?(type?==?UserType.PLATINUM_VIP.getCode())?{
          ????????strategy?=?new?PlatinumStrategy();
          ????}?else?{
          ????????strategy?=?new?OrdinaryStrategy();
          ????}

          ????return?strategy.compute(money);
          }
          還記得我在第一篇中說到的衛(wèi)語句嗎?我們?cè)谶@里把 money < 1000 的情況提前 return。更關(guān)注于滿1000邏輯 ,也可以減少不必要的縮進(jìn)。

          深思

          我曾一度 以為 策略模式不過如此。以為代碼優(yōu)化到這已經(jīng)可以了。但是還有一個(gè)恐怖的事情,if-else 依然存在 :)我嘗試翻閱了許多書籍,查看如何消除 策略模式中的 if-else書中大部分的方法是,使用簡(jiǎn)單工廠 + 策略模式。把 if - else 切換為 switch 創(chuàng)建一個(gè)工廠方法而已。但是這遠(yuǎn)遠(yuǎn)沒有達(dá)到我想要的效果,打倒 if - else直到某一天夜里,我大佬在群里分享一個(gè) Java8 小技巧時(shí),從此開新世界。

          工廠 + 策略

          public?interface?Strategy?{

          ????double?compute(long?money);

          ????//?返回?type
          ????int?getType();
          }


          public?class?OrdinaryStrategy?implements?Strategy?{

          ????@Override
          ????public?double?compute(long?money)?{
          ????????System.out.println("普通會(huì)員?不打折");
          ????????return?money;
          ????}

          ????//?添加?type?返回
          ????@Override
          ????public?int?getType()?{
          ????????return?UserType.SILVER_VIP.getCode();
          ????}
          }

          public?class?SilverStrategy?implements?Strategy?{

          ????@Override
          ????public?double?compute(long?money)?{

          ????????System.out.println("白銀會(huì)員?優(yōu)惠50元");
          ????????return?money?-?50;
          ????}

          ????//?type?返回
          ????@Override
          ????public?int?getType()?{
          ????????return?UserType.SILVER_VIP.getCode();
          ????}
          }

          ....省略剩下?Strategy
          我們先在 Strategy 新增一個(gè) getType 方法,用來表示?該策略的 type 值。代碼相對(duì)簡(jiǎn)單,這里就不過多介紹了
          public?class?StrategyFactory?{

          ????private?Map?map;

          ????public?StrategyFactory()?{

          ????????List?strategies?=?new?ArrayList<>();

          ????????strategies.add(new?OrdinaryStrategy());
          ????????strategies.add(new?SilverStrategy());
          ????????strategies.add(new?GoldStrategy());
          ????????strategies.add(new?PlatinumStrategy());
          ????????strategies.add(new?PlatinumStrategy());

          ????????//?看這里?看這里?看這里!
          ????????map?=?strategies.stream().collect(Collectors.toMap(Strategy::getType,?strategy?->?strategy));

          ????????/*?等同上面
          ????????map?=?new?HashMap<>();
          ????????for?(Strategy?strategy?:?strategies)?{
          ????????????map.put(strategy.getType(),?strategy);
          ????????}*/

          ????}

          ????public?static?class?Holder?{
          ????????public?static?StrategyFactory?instance?=?new?StrategyFactory();
          ????}

          ????public?static?StrategyFactory?getInstance()?{
          ????????return?Holder.instance;
          ????}

          ????public?Strategy?get(Integer?type)?{
          ????????return?map.get(type);
          ????}
          }
          靜態(tài)內(nèi)部類單例,單例模式實(shí)現(xiàn)的一種,不是本文重點(diǎn),如不了解,可以自行 google我們?cè)僦謩?chuàng)建一個(gè) StrategyFactory 工廠類。StrategyFactory 這里我使用的是靜態(tài)內(nèi)部類單例,在構(gòu)造方法的時(shí)候,初始化好 需要的 Strategy,并把 list 轉(zhuǎn)化為 map。這里 轉(zhuǎn)化就是“靈魂”所在。

          toMap

          我們先來看看 Java8 語法中的小技巧。
          通常情況下,我們遍歷 List,手動(dòng)put到 Map 中。
          --------------??before?-----------------

          map?=?new?HashMap<>();
          for?(Strategy?strategy?:?strategies)?{
          ????map.put(strategy.getType(),?strategy);
          }

          --------------??after?Java8?-----------------

          map?=?strategies.stream().collect(Collectors.toMap(Strategy::getType,?strategy?->?strategy));
          toMap 第一個(gè)參數(shù)是一個(gè)Function,對(duì)應(yīng) Map 中的 key,第二個(gè)參數(shù)也是一個(gè)Function,strategy -> strategy, 左邊strategy 是遍歷 strategies 中的每一個(gè)strategy,右邊strategy則是 Map 對(duì)應(yīng) value 值。若是不了解 Java8 語法的朋友,強(qiáng)烈建議看 《Java8 實(shí)戰(zhàn)》,書中詳細(xì)的介紹了 Lambda表達(dá)式、Stream等語法。

          效果

          private?static?double?getResult(long?money,?int?type)?{

          ????if?(money?1000
          )?{
          ????????return?money;
          ????}

          ????Strategy?strategy?=?StrategyFactory.getInstance().get(type);

          ????if?(strategy?==?null){
          ????????throw?new?IllegalArgumentException("please?input?right?type");
          ????}

          ????return?strategy.compute(money);
          }
          至此,通過一個(gè)工廠類,在我們?cè)?getResult()調(diào)用的時(shí)候,根據(jù)傳入 type,即可獲取到 對(duì)應(yīng) Strategy再也沒有可怕的 if-else 語句。完結(jié)撒花撒花 : )

          后續(xù)

          后續(xù)代碼優(yōu)化上,若是 Java 項(xiàng)目,可以嘗試使用自定義注解,注解 Strategy 實(shí)現(xiàn)類。這樣可以簡(jiǎn)化原來需在工廠類 List 添加一個(gè) Stratey 策略。

          最后

          以上就是我在開發(fā)中遇到復(fù)雜的 if-else 語句“優(yōu)雅處理”思路,如有不妥,歡迎大家一起交流學(xué)習(xí)。

          94aacac76e4dcc2afe449a9f9031b78a.webp

          近期精彩內(nèi)容推薦:??

          f508b1f04bc44eabcf206fac39b2c85c.webp?Python是一門神奇的語言!f508b1f04bc44eabcf206fac39b2c85c.webp?IntelliJ IDEA 的 2020 ,真的很牛皮!f508b1f04bc44eabcf206fac39b2c85c.webp?刪庫跑路真的發(fā)生,技術(shù)總監(jiān)干的!f508b1f04bc44eabcf206fac39b2c85c.webp?2020年Java框架排行榜,誰居榜首?



          e4e64155505c04e28ccb4f74c6bdeff5.webp

          在看點(diǎn)這里fd4702b2a008bf463de11f73a47e4679.webp好文分享給更多人↓↓

          瀏覽 26
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻妃三级片 | 人妻精品综合 码 | 狼色视频| 国产高清日韩无码 | 天天干天天干天天干天天 |