通過(guò)行為參數(shù)化傳遞代碼

行為參數(shù)化是可以幫助你處理頻繁變更的需求的一種軟件開(kāi)發(fā)模式

引言

1.首先我們看下實(shí)現(xiàn)從蘋(píng)果列表中選出所有的綠色的蘋(píng)果的代碼

public static List<Apple> filterGreenApples(List<Apple> inventory){
        //存儲(chǔ)所有選出的蘋(píng)果
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            //選出綠色蘋(píng)果
            if("green".equals(apple.getColor())){
                result.add(apple);
            }
        }
        return result;
    }

結(jié)果輸出

public static void main(String[] args) {
        // 蘋(píng)果列表
        List<Apple> list = Arrays.asList(new Apple(80,"green"),new Apple(155,"green"),new Apple(120,"red"));
        //挑選蘋(píng)果
        List<Apple> listGreen = filterGreenApples(list);
        for(Apple apple:listGreen){
            System.out.println("蘋(píng)果顏色是:"+apple.getColor()+"褐捻;重量是"+apple.getWeight()+"g狸驳。");
        }
    }
//執(zhí)行結(jié)果
蘋(píng)果顏色是:green;重量是80g状知。
蘋(píng)果顏色是:green;重量是155g孽查。

2.當(dāng)我們只有這一個(gè)需求的時(shí)候饥悴,上述實(shí)現(xiàn)沒(méi)有問(wèn)題,如果我們需要篩選紅色的蘋(píng)果呢,那我們可以將顏色作為參數(shù)進(jìn)行實(shí)現(xiàn)

    public static List<Apple> filterGreenApples(List<Apple> inventory,String color){
        //存儲(chǔ)所有選出的蘋(píng)果
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            //選出顏色為color的蘋(píng)果
            if(apple.getColor().equals(color)){
                result.add(apple);
            }
        }
        return result;
    }

此時(shí)我們可以通過(guò)顏色挑選蘋(píng)果

//挑選綠色蘋(píng)果
 List<Apple> listGreen = filterGreenApples(list,"green");
//挑選紅色蘋(píng)果
 List<Apple> listRed = filterGreenApples(list,"red");
//挑選xx顏色的蘋(píng)果
 List<Apple> listRed = filterGreenApples(list,"xx");
……

3.這時(shí)候我們又有新的需求來(lái)了西设,我們要根據(jù)蘋(píng)果的重量來(lái)篩選瓣铣,比如篩選重量大于150的蘋(píng)果,我們根據(jù)上面的解決辦法贷揽,實(shí)現(xiàn)如下:

public static List<Apple> filterGreenApples(List<Apple> inventory, int weight){
        //存儲(chǔ)所有選出的蘋(píng)果
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            //選出重量大于weight的蘋(píng)果
            if(apple.getWeight()>weight){
                result.add(apple);
            }
        }
        return result;
    }

此時(shí)我們可以通過(guò)蘋(píng)果的重量挑選蘋(píng)果

//挑選蘋(píng)果
        List<Apple> listWeight = filterGreenApples(list,150);
//執(zhí)行結(jié)果

4.那么當(dāng)我們想要既能通過(guò)蘋(píng)果的重量篩選&也能通過(guò)顏色進(jìn)行篩選呢棠笑?我們需要添加上述2和3的兩個(gè)代碼;當(dāng)然擒滑,我們還是可以根據(jù)上面的思路腐晾,然后增加一個(gè)標(biāo)志位來(lái)判斷是根據(jù)顏色還是根據(jù)重量篩選,實(shí)現(xiàn)如下:

public static List<Apple> filterGreenApples(List<Apple> inventory, String color,int weight,boolean flag){
        //存儲(chǔ)所有選出的蘋(píng)果
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            // 參數(shù)flag表示標(biāo)志位丐一,flag為true表示通過(guò)顏色篩選藻糖,false表示通過(guò)重量篩選
            if((flag && apple.getColor().equals(color))||(!flag && apple.getWeight()>weight)){
                result.add(apple);
            }
        }
        return result;
    }

調(diào)用方式如下:

// 通過(guò)顏色篩選
List<Apple> listColor = filterGreenApples(list,"green",150,true);
// 通過(guò)重量篩
List<Apple> listWeight = filterGreenApples(list,"green",150,false);

建議最好不要這樣用,首先可讀性不強(qiáng)库车,flag的true和false分別代表什么呢巨柒?其次,當(dāng)Apple含有其他屬性時(shí)(比如產(chǎn)地柠衍、甜度等)洋满,編寫(xiě)的代碼就會(huì)比較復(fù)雜,這時(shí)候就需要引入“行為參數(shù)化”這個(gè)開(kāi)發(fā)模式珍坊,行為參數(shù)化就是用來(lái)處理頻繁變更的需求的開(kāi)發(fā)模式牺勾。

行為參數(shù)化傳遞參數(shù)的方式

1.建模,即選擇的蘋(píng)果的策略

引言中我們使用的方式是“值的參數(shù)化”阵漏,這種方式并不靈活驻民,我們需要將蘋(píng)果的屬性抽象出來(lái)(不考慮實(shí)際有哪些屬性),返回一個(gè)boolean值履怯,告訴用戶(hù)是否滿(mǎn)足篩選條件(即符合這個(gè)屬性)回还;這就是一個(gè)抽象的標(biāo)準(zhǔn),我們通過(guò)這個(gè)標(biāo)準(zhǔn)建模:

public interface ApplePredicate {
    // 任何類(lèi)要實(shí)現(xiàn)此接口都要實(shí)現(xiàn)test方法叹洲,傳入的參數(shù)必須是Apple類(lèi)型柠硕,返回值為boolean
    boolean test (Apple apple);
}

2.使用多個(gè)實(shí)現(xiàn)實(shí)現(xiàn)不同的選擇標(biāo)準(zhǔn)

這時(shí)候我們可以通過(guò)接口的實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)多個(gè)篩選標(biāo)準(zhǔn)了,比如我們需要篩選出重的蘋(píng)果运提,那我們就可以這樣實(shí)現(xiàn):

public class AppleHeavyWeightPredicate implements ApplePredicate {
    @Override
    public boolean test(Apple apple) {
        return apple.getWeight()>150;
    }
}

篩選出綠色的蘋(píng)果的實(shí)現(xiàn)如下:

public class AppleGreenColorPredicate implements ApplePredicate {
    @Override
    public boolean test(Apple apple) {
        return "green".equals(apple.getColor());
    }
}

3.傳遞代碼
這時(shí)候我們將ApplePredicate進(jìn)行了各種實(shí)現(xiàn)蝗柔,我們?cè)趺蠢眠@些實(shí)現(xiàn)來(lái)達(dá)到我們篩選的目的呢?我們需要給filterApples方法添加一個(gè)參數(shù)民泵,讓它接收ApplePredicate對(duì)象诫咱,對(duì)Apple對(duì)象進(jìn)行條件測(cè)試。這就是行為參數(shù)化:讓方法接受多種行為(或戰(zhàn)略)作為參數(shù)洪灯,并在內(nèi)部使用坎缭,來(lái)完成不同的行為竟痰。那我們看下修改后的filterApples方法:

 public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate p){
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            //ApplePredicate對(duì)象p封裝了測(cè)試蘋(píng)果的條件
            if(p.test(apple)){
                result.add(apple);
            }
        }
        return result;
    }
  • 傳遞代碼/行為
//首先AppleHeavyWeightPredicate和AppleGreenColorPredicate都是ApplePredicate的實(shí)現(xiàn)類(lèi)
        ApplePredicate p1 = new AppleHeavyWeightPredicate();
        ApplePredicate p2 = new AppleGreenColorPredicate();

看到這邊相信大家都知道下一步怎么用這個(gè)方式來(lái)篩選一個(gè)綠色的蘋(píng)果了

        List<Apple> listGreen = filterApples(list,new AppleGreenColorPredicate());

這表明filterApples方法的行為取決于你通過(guò)ApplePredicate對(duì)象傳遞的代碼,這就相當(dāng)于你把filterApple方法行為參數(shù)化了掏呼。
其實(shí)在這個(gè)例子當(dāng)中坏快,最重要的就是test方法的實(shí)現(xiàn),它定義了filterApples方法的新行為憎夷,但是filterApples只能接受對(duì)象莽鸿,所以我們必須把test方法實(shí)現(xiàn)的代碼包裹在ApplePredicate對(duì)象里,即我們通過(guò)一個(gè)實(shí)現(xiàn)了test方法的對(duì)象來(lái)傳遞布爾表達(dá)式拾给,這種做法類(lèi)似于用在“傳遞代碼”祥得。通過(guò)下面的圖我們形象的看一下


image.png
  • 多種行為,一個(gè)參數(shù)
    行為參數(shù)化的好處在于你可以把迭代要篩選的集合的邏輯與對(duì)集合中么個(gè)元素應(yīng)用的行為區(qū)分開(kāi)來(lái)蒋得,這樣我們可以重復(fù)使用同一個(gè)方法级及,給它不同的行為來(lái)達(dá)到不同的目的。


    image.png

    4.優(yōu)化代碼
    通過(guò)上面這種實(shí)現(xiàn)方式额衙,雖然可以讓代碼適應(yīng)需求的變化饮焦,但是這個(gè)過(guò)程很啰嗦,我們需要聲明很多只要實(shí)例化一次的類(lèi)窍侧。這時(shí)候我們就想到了java中的匿名類(lèi)县踢。那我們的實(shí)現(xiàn)如下:
    定義篩選標(biāo)準(zhǔn)建模&filterApples實(shí)現(xiàn)方式不變,只是將需要實(shí)例化的類(lèi)使用匿名類(lèi)聲明

//篩選紅色蘋(píng)果
        List<Apple> listRed= filterApples(list, new ApplePredicate() {
            @Override
            public boolean test(Apple apple) {
                return "red".equals(apple.getColor());
            }
        });

這種方式雖然省去了聲明類(lèi)的這個(gè)步驟伟件,但是還是也還是存在不易讀以及笨重的問(wèn)題硼啤,java8中通過(guò)lambda表達(dá)式很好的解決了這個(gè)問(wèn)題,讓代碼看起來(lái)更干凈斧账。
上述代碼可以使用lambda重寫(xiě)如下:

//篩選紅色蘋(píng)果
        List<Apple> listRed2= filterApples(list,(Apple apple)->"red".equals(apple.getColor()));

5.list類(lèi)型的抽象化
進(jìn)行過(guò)上述抽象后谴返,filterApples方法只適用于Apple,我們還可以通過(guò)將list類(lèi)型抽象化其骄,使我們的代碼更加靈活亏镰。

  • 抽象標(biāo)準(zhǔn)建模
public interface Predicate<T> {
    boolean test(T t);
}
  • 抽象filter方法
public static <T> List<T> filter(List<T> list,Predicate<T> p){
        List<T> result = new ArrayList<>();
        for(T e:list){
            if(p.test(e)){
                result.add(e);
            }
        }
        return result;
    }
  • 調(diào)用方式一致
//篩選紅色蘋(píng)果
        List<Apple> listRed= filterApples(list,(Apple apple)->"red".equals(apple.getColor()));

這時(shí)候filter方法就不僅僅可以用于Apple的列表了扯旷,香蕉拯爽、橘子等都可以適用了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末钧忽,一起剝皮案震驚了整個(gè)濱河市毯炮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耸黑,老刑警劉巖桃煎,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異大刊,居然都是意外死亡为迈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)葫辐,“玉大人搜锰,你說(shuō)我怎么就攤上這事」⒄剑” “怎么了蛋叼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)剂陡。 經(jīng)常有香客問(wèn)我狈涮,道長(zhǎng),這世上最難降的妖魔是什么鸭栖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任歌馍,我火速辦了婚禮,結(jié)果婚禮上纤泵,老公的妹妹穿的比我還像新娘骆姐。我一直安慰自己,他們只是感情好捏题,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布玻褪。 她就那樣靜靜地躺著,像睡著了一般公荧。 火紅的嫁衣襯著肌膚如雪带射。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天循狰,我揣著相機(jī)與錄音窟社,去河邊找鬼。 笑死绪钥,一個(gè)胖子當(dāng)著我的面吹牛灿里,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播程腹,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼匣吊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了寸潦?” 一聲冷哼從身側(cè)響起色鸳,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎见转,沒(méi)想到半個(gè)月后命雀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斩箫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年吏砂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撵儿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狐血,死狀恐怖统倒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情氛雪,我是刑警寧澤房匆,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站报亩,受9級(jí)特大地震影響浴鸿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜弦追,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一岳链、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧劲件,春花似錦掸哑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至牵辣,卻和暖如春摔癣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纬向。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工择浊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逾条。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓琢岩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親师脂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子担孔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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

  • Java8提出了三個(gè)新概念:流處理、行為參數(shù)化危彩、并行處理攒磨。 目錄 什么是行為參數(shù)化泳桦?行為參數(shù)化的好處是什么汤徽?應(yīng)對(duì)不...
    七月_3155閱讀 572評(píng)論 2 3
  • 在實(shí)習(xí)的這一段時(shí)間里,我深刻體會(huì)到一個(gè)道理灸撰,就是用戶(hù)的需求不斷的在變化谒府,因而自己的代碼也要進(jìn)行重構(gòu)拼坎,這說(shuō)明了一個(gè)問(wèn)...
    freelands閱讀 3,426評(píng)論 8 9
  • 通過(guò)行為參數(shù)化傳遞代碼 行為參數(shù)化是可以幫助你處理頻繁變更的需求的一種軟件開(kāi)發(fā)模式。它意味著拿出一個(gè)代碼塊完疫,將它準(zhǔn)...
    謝隨安閱讀 1,286評(píng)論 0 0
  • 綠減無(wú)重?cái)?shù)泰鸡, 寒高百蟲(chóng)絕。 冬來(lái)自春秋壳鹤, 焉知惹孤鴻盛龄。
    影射小樓閱讀 348評(píng)論 0 0
  • 2018年1月7日 星期日 陰轉(zhuǎn)小雪 親子日記第九十八篇 今天好冷,趕上發(fā)貨裝車(chē)芳誓,下班六點(diǎn)了余舶。回到家...
    人弋三壽閱讀 149評(píng)論 0 0