反饋法學(xué)習(xí)設(shè)計(jì)模式(一)——策略模式Strategy Pattern

簡介(Introduction)

之前學(xué)習(xí)Java8實(shí)戰(zhàn)時(shí)个唧,遇到一個(gè)很好的策略模式示例钥顽。便想著借著這個(gè)示例結(jié)合反饋式的方法來坟冲,學(xué)習(xí)策略設(shè)計(jì)模式睛挚,也以便后面反復(fù)琢磨學(xué)習(xí)邪蛔。
首先我們通過練習(xí),逐步寫出符合相應(yīng)需求的代碼扎狱,再根據(jù)需求進(jìn)行改進(jìn)侧到、比較、重寫淤击,最終得出一種更靈活的最佳實(shí)現(xiàn)床牧。

練習(xí)

    /** 該類為蘋果 */
    class Apple {
        private Float weight;
        private String color;
    }
    /** 該類為蘋果過濾器 */
    public class AppleFilter {
        private Set<Apple> apples;
    }
  • 需求一,添加方法使得可以篩選綠蘋果
  • 需求二遭贸,能夠選取各種顏色的蘋果
  • 需求三,能夠篩選各種顏色, 各種重量的蘋果
  • 需求四心软,將篩選條件進(jìn)行抽象壕吹,能篩選各種屬性
  • 需求五,使用匿名類進(jìn)行改進(jìn)

策略模式(Strategy Pattern)

對(duì)于策略模式删铃,我的理解是行為參數(shù)化耳贬。行為是指處理頻繁變化需求的那段代碼。每當(dāng)需求變化時(shí)猎唁,就傳遞不同的行為作為參數(shù)進(jìn)行處理咒劲。如此,便是將代碼塊進(jìn)行封裝诫隅,得到可進(jìn)行應(yīng)對(duì)變化的策略一般腐魂。

策略模式,它定義了算法家族逐纬。分別封裝起來蛔屹,讓它們之間可以相互替換,此模式讓算法的變換豁生,不會(huì)影響到使用算法的客戶端兔毒。——《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》

  • 解決什么矛盾:不同時(shí)間應(yīng)用不同的業(yè)務(wù)規(guī)則甸箱;多重條件判斷育叁、硬編碼所帶來的復(fù)雜及難以維護(hù)
  • 如何用代碼實(shí)現(xiàn):每個(gè)策略,實(shí)現(xiàn)約定的接口及方法芍殖。
  • 優(yōu)點(diǎn):耦合性低(降低各種策略類與調(diào)用者的耦合)豪嗽、擴(kuò)展性強(qiáng)、代碼簡潔(策略封裝了變化的條件、避免了多重判斷)
  • 缺點(diǎn):策略類膨脹昵骤、代碼繁瑣

UML

策略模式.PNG

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

  • 代碼目錄結(jié)構(gòu)


    目錄結(jié)構(gòu).png
  • 核心代碼树碱,具體詳見github

package Demo.filter;

/**
 * 該類用于篩選蘋果
 * 代碼質(zhì)量要求:更加抽象通用, 更加簡潔
 * 以下七次的代碼修改也相應(yīng)反映代碼的質(zhì)量及水平
 *
 * Created by auhnayuil on 17-9-24.
 */
public class FilterApple implements Filter<Apple> {

    /**
     * 第一次需求:選取綠色蘋果
     * 該方法純粹為篩選出綠色蘋果
     * 篩選蘋果的條件為常量, 很難適應(yīng)客戶或者調(diào)用者的需求變化
     */
    public Set<Apple> filterGreenApple(Set<Apple> apples){
        Set<Apple> result = new HashSet<>();
        for(Apple apple : apples){
            if("green".equals(apple.getColor()))
                result.add(apple);
        }
        return result;
    }

    /**
     * 第二次需求變化:能夠選取各種顏色的蘋果
     * 將顏色提取為方法的參數(shù), 更靈活地適應(yīng)篩選各種顏色的蘋果
     *
     * 一個(gè)良好的原則是在編寫某個(gè)需求多變的代碼時(shí), 嘗試將其抽象化
     */
    public Set<Apple> filterAppleByColor(Set<Apple> apples, String color){
        Set<Apple> result = new HashSet<>();
        for(Apple apple : apples){
            if(apple.getColor().equals(color))
                result.add(apple);
        }
        return result;
    }

    /**
     * 第三次需求變化:能夠篩選各種顏色, 各種重量的蘋果
     * 需求變化的因素除了單一元素上變化, 還表現(xiàn)為多元素上變化
     *
     * 一旦多屬性被要求組合查詢, 進(jìn)行更復(fù)雜的查詢時(shí)
     * 篩選條件及使用上將會(huì)變得非常笨拙及丑陋
     */
    public Set<Apple> filterApples(Set<Apple> apples, String color, Float weight){
        Set<Apple> result = new HashSet<>();
        for(Apple apple : apples){
            if(     apple.getColor().equals(color)
                    && apple.getWeight() > weight)
                result.add(apple);
        }
        return result;
    }

    /**
     * 第四次嘗試:將篩選條件進(jìn)行抽象, 將行為參數(shù)化
     * 更高層次的抽象為將選擇條件進(jìn)行建模, 即形成一種可進(jìn)行選擇的通用的策略
     *
     * 模型描述:根據(jù)對(duì)象的某些屬性來返回一個(gè)布爾值
     * 類似于"謂詞"這樣的語義
     *
     * 至于為何要在方法參數(shù)中抽象篩選條件為一個(gè)接口?
     *
     * 到這里, filterApples的行為僅取決于 Predicate對(duì)象所傳遞的代碼, 也就是
     * 所謂的 向一個(gè)參數(shù)傳遞了代碼, 或者行為參數(shù)化了
     *
     * 值需要?jiǎng)?chuàng)建包裹著不同篩選條件的代碼塊 的Predicate對(duì)象就可以實(shí)現(xiàn)不同的行為了
     */
    public List<Apple> filterApples(List<Apple> apples, Predicate<Apple> predicate){
        return (List<Apple>) collect(apples, predicate);
    }

    /**
     * 第五嘗試:匿名類
     * 沒有變量名, 允許你同時(shí)聲明并實(shí)例化一個(gè)類
     *
     */
    public Set<Apple> filterApplesByAnonymousClass(Set<Apple> apples){
        return (Set<Apple>) collect(apples, new Predicate<Apple>() {
            @Override
            public boolean test(Apple target) {
                return ("red".equals(target.getColor()) && target.getWeight() > 0.0F);
            }
        });
    }

    /**
     *  第六次嘗試:Lambda表達(dá)式 以及 抽象結(jié)果集
     *  可以改寫為以下形式:
     *  filterApplesByLambda(apples, (Apple apple) -> "red".equals(apple.getColor()));
     *
     *  那么如何用Lambda改寫一個(gè)內(nèi)部類变秦?
     */
    public Set<Apple> filterApplesByLambda(Collection<Apple> apples, boolean is){
        Set<Apple> result = new HashSet<>();
        for(Apple apple : apples){
            if(is)
                result.add(apple);
        }
        return result;
    }
}

package Demo.filter;

/**
 * 該方法為最基本的過濾器
 * 用于抽象各個(gè)過濾器中的循環(huán), 遍歷, 收集等重復(fù)行為
 * 采用接口的默認(rèn)方法實(shí)現(xiàn)
 *
 * Created by auhnayuil on 17-9-24.
 */
public interface Filter<T> {

    default Collection<T> collect(Collection<T> targets, Predicate<T> predicate) {
        Class<? extends Collection> clazz = targets.getClass();
        Collection result = null;
        try {
             //該部分代碼塊, 通過反射生成集合的實(shí)例對(duì)象. 得到一個(gè)空的結(jié)果集對(duì)象
             result = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        for(T target : targets){
            //循環(huán)遍歷目標(biāo)集合, 并且通過接口形成策略判斷是否符合過濾器條件
            //收集符合條件的結(jié)果
            if(predicate.test(target))
                result.add(target);
        }
        return result;
    }
}
package Demo.predicate;

/**
 * 策略設(shè)計(jì)模式(Staregy)
 * 定義了一系列的算法族, 并將其封裝, 可以相互替換且在運(yùn)行時(shí)選擇所需要的合適的"策略"
 * Created by auhnayuil on 17-9-24.
 */
public class AppleRedAndWeightPrdicate implements Predicate<Apple> {

    @Override
    public boolean test(Apple target) {
        return ("red".equals(target.getColor())
                && target.getWeight() > 0.0F);
    }
}

參考鏈接

[Java8實(shí)戰(zhàn)] https://book.douban.com/subject/26772632/
[Baidu] https://baike.baidu.com/item/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/646307?fr=aladdin
[菜鳥教程] http://www.runoob.com/design-pattern/strategy-pattern.html

最后編輯于
?著作權(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)容

  • 設(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
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,127評(píng)論 25 707
  • 1 場景問題 1.1 報(bào)價(jià)管理 向客戶報(bào)價(jià)娶眷,對(duì)于銷售部門的人來講,這是一個(gè)非常重大啸臀、非常復(fù)雜的問題届宠,對(duì)不同的客戶要...
    4e70992f13e7閱讀 3,087評(píng)論 2 16
  • 第一保持正念 第二練習(xí)幸福的能力 第三練習(xí)終結(jié)拖延癥 第四跟身邊的人分享戒煙的方法啊 第五就是接著練習(xí)有效溝通了豌注。...
    Miranda分享閱讀 302評(píng)論 0 0