Android 策略模式

源碼地址

介紹

策略模式定義了一系列算法,并將每一個(gè)算法封裝起來,而且使它們還可以相互替換箩兽。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化

使用場景

  • 針對(duì)同一類型的多種處理方式钦扭,僅僅是具體行為有差別時(shí)。
  • 需要安全地封裝多種同一類型的操作時(shí)。
  • 出現(xiàn)同一抽象類有多個(gè)子類,而又需要使用 if-else 或者 switch-case 來選擇具體子類時(shí)。

角色介紹

  • Context——用來操作策略的上下文環(huán)境褪秀;
  • Strategy——策略的抽象;
  • ConcreteStrategyA薛训,ConcreteStrategyB——具體的策略實(shí)現(xiàn)媒吗。

簡單實(shí)現(xiàn)

需求:下面以坐公交工具的費(fèi)用計(jì)算來演示。

第一個(gè)版本的代碼:

public class PriceCalculator {
    //公交車類型
    private static final int BUS = 1;
    //地鐵類型
    private static final int SUBWAY = 2;

    /**
     * 公交車乙埃,十公里之內(nèi)一元錢闸英,超過十公里之后每加一元錢可以乘5公里
     * @param km   公里
     * @return
     */
    private int busPrice(int km) {
        //超過十公里的總距離
        int extraTotal = km - 10;
        //超過的距離是5公里的倍數(shù)
        int extraFactor = extraTotal / 5;
        //超過的距離對(duì)5公里取余
        int fraction = extraTotal % 5;
        //價(jià)格計(jì)算
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price;
    }

    /**
     * 6公里(含)內(nèi)3元;6~12公里(含)4元膊爪;12~22公里(含)5元自阱;22~32公里(含)6元;
     * @param km    公里
     * @return
     */
    private int subwayPrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km <= 12) {
            return 4;
        } else if (km <= 22) {
            return 5;
        } else if (km <= 32) {
            return 6;
        }
        //其他距離簡化為7元
        return 7;
    }

    private int calculatePrice(int km, int type) {
        if (type == BUS) {
            return busPrice(km);
        } else if (type == SUBWAY) {
            return subwayPrice(km);
        }
        return 0;
    }

    public static void main(String[] args) {
        PriceCalculator calculator = new PriceCalculator();
        System.out.println("坐16公里的公交車票價(jià)為:" + calculator.calculatePrice(16, BUS));
        System.out.println("坐16公里的地鐵票價(jià)為:" + calculator.calculatePrice(16, SUBWAY));
    }
}

當(dāng)增加一種出行方式時(shí)米酬,如出租車沛豌,那么就需要在 PriceCalculator 中增加一個(gè)方法來計(jì)算出租車出行的價(jià)格,并且在 calculatePrice 函數(shù)中增加一個(gè)判斷,新增代碼大致如下:

public class PriceCalculator {
    //公交車類型
    private static final int BUS = 1;
    //地鐵類型
    private static final int SUBWAY = 2;
    //出租車類型
    private static final int TAXI = 3;

    private int taxiPrice(int km) {
        return km * 2;
    }
  
    private int calculatePrice(int km, int type) {
        if (type == BUS) {
            return busPrice(km);
        } else if (type == SUBWAY) {
            return subwayPrice(km);
        } else if (type == TAXI) {
            return taxiPrice(km);
        }
        return 0;
    }
}

當(dāng)修改計(jì)算方式或者增加出行方式時(shí)加派,有需要增加 if-else 代碼叫确,這樣會(huì)使得代碼變得難以維護(hù)。

下面為策略模式實(shí)現(xiàn)代碼:

  1. 計(jì)算接口

    public interface CalculateStrategy {
        /**
         * 按距離來計(jì)算價(jià)格
         * @param km    公里
         * @return  返回價(jià)格
         */
        int calculatePrice(int km);
    }
    
  2. 公交車價(jià)格計(jì)算策略

    public class BusStrategy implements CalculateStrategy {
        /**
         * 公交車芍锦,十公里之內(nèi)一元錢竹勉,超過十公里之后每加一元錢可以乘5公里
         * @param km   公里
         * @return
         */
        @Override
        public int calculatePrice(int km) {
            //超過十公里的總距離
            int extraTotal = km - 10;
            //超過的距離是5公里的倍數(shù)
            int extraFactor = extraTotal / 5;
            //超過的距離對(duì)5公里取余
            int fraction = extraTotal % 5;
            //價(jià)格計(jì)算
            int price = 1 + extraFactor * 1;
            return fraction > 0 ? ++price : price;
        }
    }
    
  3. 地鐵價(jià)格計(jì)算策略

    public class SubwayStrategy implements CalculateStrategy {
        /**
         * 6公里(含)內(nèi)3元;6~12公里(含)4元娄琉;12~22公里(含)5元次乓;22~32公里(含)6元;
         * @param km    公里
         * @return
         */
        @Override
        public int calculatePrice(int km) {
            if (km <= 6) {
                return 3;
            } else if (km <= 12) {
                return 4;
            } else if (km <= 22) {
                return 5;
            } else if (km <= 32) {
                return 6;
            }
            //其他距離簡化為7元
            return 7;
        }
    }
    
  4. 出行計(jì)算器

    public class TranficCalculator {
        private CalculateStrategy mStrategy;
        public void setStrategy(CalculateStrategy strategy) {
            mStrategy = strategy;
        }
    
        public int calculatePrice(int km) {
            return mStrategy.calculatePrice(km);
        }
    
        public static void main(String[] args) {
            TranficCalculator calculator = new TranficCalculator();
            calculator.setStrategy(new BusStrategy());
            System.out.println("公交車乘坐16公里的價(jià)格:" + calculator.calculatePrice(16));
    
            calculator.setStrategy(new SubwayStrategy());
            System.out.println("地鐵乘坐16公里的價(jià)格:" + calculator.calculatePrice(16));
    }
    

    如果需要增加一個(gè)出租車計(jì)算策略類孽水,代碼如下:

  5. 出租車計(jì)算策略

    public class TaxiStrategy implements CalculateStrategy {
        @Override
        public int calculatePrice(int km) {
            return km * 2;
        }
    }
    
  6. 出行價(jià)格計(jì)算器

    public class TranficCalculator {
        private CalculateStrategy mStrategy;
        public void setStrategy(CalculateStrategy strategy) {
            mStrategy = strategy;
        }
    
        public int calculatePrice(int km) {
            return mStrategy.calculatePrice(km);
        }
    
        public static void main(String[] args) {
            TranficCalculator calculator = new TranficCalculator();
            calculator.setStrategy(new TaxiStrategy());
            System.out.println("出租車乘坐16公里的價(jià)格:" + calculator.calculatePrice(16));
        }
    }
    

從上面可以看出票腰,使用 if-else 來解決問題,優(yōu)點(diǎn)是實(shí)現(xiàn)簡單女气,層級(jí)單一杏慰;但缺點(diǎn)也很明顯,即代碼臃腫炼鞠,邏輯復(fù)雜缘滥,難以升級(jí)與維護(hù),沒有結(jié)構(gòu)可言谒主。

后者是通過建立抽象朝扼,將不同的策略構(gòu)建成一個(gè)具體的策略實(shí)現(xiàn),通過不同的策略實(shí)現(xiàn)算法替換瘩将。在簡化邏輯吟税、結(jié)構(gòu)的同時(shí)凹耙,增強(qiáng)了系統(tǒng)的可讀性姿现、穩(wěn)定性、可擴(kuò)展性肖抱。

Android源碼中的實(shí)現(xiàn)

TimeInterpolator 時(shí)間插值器备典,用在屬性動(dòng)畫中。

總結(jié)

  • 優(yōu)點(diǎn)
    1. 結(jié)構(gòu)清晰明了意述,使用簡單直觀提佣;
    2. 耦合度相對(duì)而言較低,擴(kuò)展方便荤崇;
    3. 操作封裝也更徹底拌屏,數(shù)據(jù)更為安全。
  • 缺點(diǎn)
    1. 隨著策略的增加术荤,子類也會(huì)變得繁多倚喂。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瓣戚,隨后出現(xiàn)的幾起案子端圈,更是在濱河造成了極大的恐慌焦读,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舱权,死亡現(xiàn)場離奇詭異矗晃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宴倍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門张症,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鸵贬,你說我怎么就攤上這事吠冤。” “怎么了恭理?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拯辙,是天一觀的道長。 經(jīng)常有香客問我颜价,道長涯保,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任周伦,我火速辦了婚禮夕春,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘专挪。我一直安慰自己及志,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布寨腔。 她就那樣靜靜地躺著速侈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迫卢。 梳的紋絲不亂的頭發(fā)上倚搬,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音乾蛤,去河邊找鬼每界。 笑死,一個(gè)胖子當(dāng)著我的面吹牛家卖,可吹牛的內(nèi)容都是我干的眨层。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼上荡,長吁一口氣:“原來是場噩夢啊……” “哼趴樱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤伊佃,失蹤者是張志新(化名)和其女友劉穎窜司,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體航揉,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡塞祈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帅涂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片议薪。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖媳友,靈堂內(nèi)的尸體忽然破棺而出斯议,到底是詐尸還是另有隱情,我是刑警寧澤醇锚,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布哼御,位于F島的核電站,受9級(jí)特大地震影響焊唬,放射性物質(zhì)發(fā)生泄漏恋昼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一赶促、第九天 我趴在偏房一處隱蔽的房頂上張望液肌。 院中可真熱鬧,春花似錦鸥滨、人聲如沸嗦哆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽老速。三九已至,卻和暖如春空幻,著一層夾襖步出監(jiān)牢的瞬間烁峭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工秕铛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缩挑。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓但两,卻偏偏與公主長得像,于是被迫代替她去往敵國和親供置。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谨湘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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

  • 1 場景問題# 1.1 報(bào)價(jià)管理## 向客戶報(bào)價(jià),對(duì)于銷售部門的人來講,這是一個(gè)非常重大紧阔、非常復(fù)雜的問題坊罢,對(duì)不同的...
    七寸知架構(gòu)閱讀 5,079評(píng)論 9 62
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,744評(píng)論 0 33
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理擅耽,服務(wù)發(fā)現(xiàn)活孩,斷路器,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法乖仇,類相關(guān)的語法憾儒,內(nèi)部類的語法,繼承相關(guān)的語法乃沙,異常的語法起趾,線程的語...
    子非魚_t_閱讀 31,630評(píng)論 18 399
  • 關(guān)于作者 錢鐘書,中國現(xiàn)代文學(xué)史上非常重要的一位“才子型”文學(xué)家警儒。他1933年從清華大學(xué)外文系畢業(yè)训裆,作為最早的庚子...
    蔚成閱讀 246評(píng)論 0 0