乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      《Java8實戰(zhàn)》-讀書筆記第二章

       滔滔不絕的濤 2018-08-03

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

      行為參數(shù)化

      在《Java8實戰(zhàn)》第二章主要介紹的是 通過行為參數(shù)化傳遞代碼,那么就來了解一下什么是 行為參數(shù)化吧。

      在軟件工程中,一個從所周知的問題就是,不管你做什么,用戶的需求總是會變的(PM的需求總是會變的)。比方說,有個應用程序是幫助農民了解自己的庫存。這位農民可能想有一個查找?guī)齑嬷兴芯G色蘋果的功能。但是到了第二天,他突然告訴你:“其實我還想找出所有重量超過150克的蘋果?!保阋幌牒唵温锊痪褪歉囊幌聴l件而已。于是過了兩天,他又說:“要是我可以篩選即使綠色的蘋果,重量也超過150克的蘋果。”,這樣頻繁的改需求也不太好,面對這樣的情況理想狀態(tài)下應該把工作量降到最低。此外,類似的功能實現(xiàn)起來應該還是很簡單,而且利于長期維護。

      行為參數(shù)化就是要幫助你處理頻繁更變的需求的一種軟件開發(fā)模式。一言以蔽之,它意味著拿出一個代碼塊,把它準備好卻不去執(zhí)行它。這個代碼塊以后可以被你程序的其他部分調用,這意味著你可以推遲這塊代碼的執(zhí)行。例如,你可以將代碼塊作為參數(shù)傳遞給另外一個方法,稍后再去執(zhí)行它。這樣,這個方法的行為就基于那塊代碼被參數(shù)化了。

      應對不斷變化的需求

      想要編寫能應對變化的需求并不容易。讓我們來看一個例子,我們將會逐漸的改進這個例子,以展示一些讓代碼更靈活的做法。就像農場庫存程序而言,你需要實現(xiàn)一個從列表中篩選綠蘋果的功能。

      篩選蘋果

      1. 篩選綠蘋果,可能你選擇最初的解決方案就是這樣:

      1. private static List<Apple> filterGreenApples(List<Apple> apples) {

      2.    List<Apple> appleList = new ArrayList<Apple>();

      3.    for (Apple apple : apples) {

      4.        if ('green'.equals(apple.getColor())) {

      5.            appleList.add(apple);

      6.        }

      7.    }

      8.    return appleList;

      9. }

      現(xiàn)在代碼中就是篩選綠蘋果。但現(xiàn)在農民改主意了,他還想要篩選紅蘋果。按照最簡單的方法就是,把方法復制一下并且改一下條件為篩選紅蘋果的條件。是的,這樣做起來很簡單,要是農民想要篩選多種顏色:青色、深紅、淡紅...這種方法就不太適合了。

      1. 優(yōu)化代碼,通過顏色作為參數(shù)篩選蘋果:

      1. private static List<Apple> filterApplesByColor(List<Apple> apples, String color) {

      2.    List<Apple> appleList = new ArrayList<Apple>();

      3.    for (Apple apple : apples) {

      4.        if (color.equals(apple.getColor())) {

      5.            appleList.add(apple);

      6.        }

      7.    }

      8.    return appleList;

      9. }

      很簡單對吧。現(xiàn)在,農民又有想法:“能篩選出輕蘋果和重蘋果就好啦!一般重蘋果的重量是150克?!蹦憧赡茉缇拖氲搅诵枰ㄟ^重量來篩選蘋果,于是你又把參數(shù)穿進來作為條件進行篩選。

      1. 將重量作為參數(shù),進行重蘋果篩選:

      1. private static List<Apple> filterApplesByWeight(List<Apple> apples, int weight) {

      2.    List<Apple> appleList = new ArrayList<Apple>();

      3.    for (Apple apple : apples) {

      4.        if (apple.getWeight() > weight) {

      5.            appleList.add(apple);

      6.        }

      7.    }

      8.    return appleList;

      9. }

      是的,解決方法很簡單,但是你復制了大部分的代碼來實現(xiàn)遍歷庫存,并對每個蘋果應用篩選條件。這樣破壞了DRY(Don't Repeat Yourself 不要重復自己)的軟件工程原則?;蛟S,你一下就想到了這辦法,將所有的參數(shù)都放在一個方法中,這樣就可以簡化很多代碼了。

      1. 第三次嘗試,對你能想到的每個屬性做篩選:

      1. private static List<Apple> filterApples(List<Apple> apples, String color, int weight, boolean flag) {

      2.    List<Apple> appleList = new ArrayList<Apple>();

      3.    for (Apple apple : apples) {

      4.        boolean result = (flag && apple.getWeight() > weight) || (!flag && color.equals(apple.getColor()));

      5.        if (result) {

      6.            appleList.add(apple);

      7.        }

      8.    }

      9.    return appleList;

      10. }

      代碼看起來很簡單,但是感覺卻是不太好。如果不把注釋寫清楚,別人閱讀你代碼時根本就不知道flag是干嘛用的。要是,農民突然又有個想法,需用通過大小、形狀、產地等條件來進行篩選怎么辦?所以,我們需要利用行為參數(shù)化來解決這個問題,提高代碼的靈活性。

      行為參數(shù)化

      目前,你需要一種比添加很多參數(shù)更好的方法來應對變化的需求。讓我們退一步來看看更高層次的抽象。一種可能解決方案是對你的懸著標準建模:你考慮的是蘋果,需要根據(jù)Apple的某些屬性(比如它是綠色的嗎?重量超過150克嗎?)來返回一個boolean值。是的,你可能已經想到了第一章中介紹到了的謂詞。

      根據(jù)謂詞進行篩選

      首先,我們應該定義一個接口來對選擇標準建模:

      1. public interface ApplePredicate {

      2.    /**

      3.     * 根據(jù)給定的參數(shù)計算此謂詞。

      4.     *

      5.     * @param apple

      6.     * @return

      7.     */

      8.    boolean test(Apple apple);

      9. }

      可以用ApplePredicate的實現(xiàn)類來代表不同的選擇標準:

      只篩選綠蘋果

      1. public class AppleGreenColorPredicate implements ApplePredicate {

      2.    @Override

      3.    public boolean test(Apple apple) {

      4.        return 'green'.equals(apple.getColor());

      5.    }

      6. }

      只篩選重蘋果

      1. public class AppleHeavyWeightPredicate implements ApplePredicate {

      2.    @Override

      3.    public boolean test(Apple apple) {

      4.        return apple.getWeight() > 150;

      5.    }

      6. }

      你可以把這些標準看作filter的不同行為。這就像策略設計模式一樣,它讓你定義一組方法,把它們封裝起來,然后在運行時選擇一個方法。這里,方法就是ApplePredicate,不同的策略就是AppleHeavyWeightPredicate和AppleGreenColorPredicate。

      你可以將filterApples方法接受一個ApplePredicate對象,對Apple做條件測試。這樣就是行為參數(shù)化:讓方法接受多種行為作為參數(shù),并在內部使用,來完成不同的行為。

      根據(jù)抽象條件篩選

      1. private static List<Apple> filterApples(List<Apple> apples, ApplePredicate<Apple> applePredicate) {

      2.    List<Apple> appleList = new ArrayList<>();

      3.    for (Apple apple : apples) {

      4.        if (applePredicate.test(apple)) {

      5.            appleList.add(apple);

      6.        }

      7.    }

      8.    return appleList;

      9. }

      代碼的傳遞/行為

      酷,這段代碼看起來很多了,讀起來、用起來也更容易!現(xiàn)在你可以創(chuàng)建不同的ApplePredicate對象,并將它們傳遞給filterApples方法。這樣就可以根據(jù)不同的條件來創(chuàng)建一個類并且實現(xiàn)ApplePredicate就可以了。

      現(xiàn)在,農民要求需要篩選紅蘋果。那么,我們就可以根據(jù)條件創(chuàng)建一個類并且實現(xiàn)ApplePredicate:

      1. public class AppleRedAndHeavyPredicate implements ApplePredicate {

      2.    @Override

      3.    public boolean test(Apple apple) {

      4.        return 'red'.equals(apple.getColor()) && apple.getWeight() > 150;

      5.    }

      6. }

      1. List<Apple> filterApples2 = filterApples(apples, new AppleRedAndHeavyPredicate());

      2. System.out.println('通過謂詞篩選紅蘋果并且是重蘋果:' filterApples2);

      酷,現(xiàn)在filterApples方法的行為已經取決于通過ApplePredicate對象來實現(xiàn)了。這就是行為參數(shù)化了!

      但是,你有沒有發(fā)現(xiàn),我們每次新增一個條件就需要新增一個類。這樣做有點太過于麻煩,或許我們可以通過Lambda,將表達式傳遞給filterApples方法,這樣就無需定義多個ApplePredicate類,從而去掉不必要的代碼,并減輕工作量。

      多種行為,一個參數(shù)

      行為參數(shù)化的好處在與你可以把迭代要篩選的集合的邏輯與對集合中每個元素應用的行為區(qū)分開來。這樣你就可以重復使用同一個方法,給它不同的行為來達到不同的目的。

      為了能夠對參數(shù)化行為運用自如,并且簡化代碼,我們來嘗試將參數(shù)通過Lambda的方式傳遞給filterApples。

      通過Lambda的方式來篩選紅蘋果:

      1. List<Apple> filterApples3 = filterApples(apples, apple -> 'red'.equals(apple.getColor()));

      通過Lambda的方式來篩選紅蘋果并且是重蘋果:

      1. List<Apple> filterApples4 = filterApples(apples, apple -> 'red'.equals(apple.getColor()) && apple.getWeight() > 150);

      是的,使用的已經還是原來的條件,并且不再需要根據(jù)不同的條件再去實現(xiàn)一個ApplePredicate類了,這樣極大的簡化了代碼。但是,農民又有一個需求了:“現(xiàn)在,不只是需要對蘋果進行篩選了,還需要對香蕉、橘子、草莓進行篩選了。”

      但是,我們目前的代碼只能夠對蘋果進行篩選而已,為了解決這個問題,我們可以將類型定義為泛型,這樣就不只是只能對蘋果進行篩選了。

      使用謂詞

      其實,我們可以不需要去定義謂詞,因為在Java中就一個了Predicate了,我們可以使用它并且實現(xiàn)我們的功能。

      定義一個泛型的filter方法:

      1. private static <T> List<T> filter(List<T> list, Predicate<T> predicate) {

      2.    List<T> result = new ArrayList<>();

      3.    for (T t : list) {

      4.        if (predicate.test(t)) {

      5.            result.add(t);

      6.        }

      7.    }

      8.    return result;

      9. }

      這個方法是一個通用的篩選方法,不只是可以用于篩選蘋果。

      篩選重蘋果:

      1. List<Apple> heavyApples = filter(apples, (Apple apple) -> apple.getWeight() > 150);

      篩選能被2整除的數(shù):

      1. List<Integer> numbers = Arrays.asList(10, 11, 8, 5, 1, 2, 29, 18);

      2. List<Integer> integerList = filter(numbers, number -> number % 2 == 0);

      是不是很酷?現(xiàn)在的代碼簡潔性和靈活性都很高,在Java8之前這些都是不可能做到的!

      現(xiàn)在,你已經感覺到了行為參數(shù)化是一個很有用的模式,它能夠輕松地適應不斷變化的需求。在Java中很多方法都可以用不同的行為來參數(shù)化,比如使用Comparator排序,用Runnable執(zhí)行一個代碼塊等等。

      使用Comparator來排序:

      1. apples.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

      或者這樣:

      1. apples.sort(Comparator.comparing(Apple::getWeight));

      使用Runnable執(zhí)行某個代碼塊:

      1. Thread t = new Thread(() -> System.out.println('HelloWorld'));

      總結

      1. 行為參數(shù)化,就是一個方法接受多個不同的行為作為參數(shù),并在內部使用它們,完成不同行為的能力。

      2. 行為參數(shù)化可以讓代碼更好的適應不斷變化的要求,減輕工作量。

      3. 傳遞代碼,就是將新行為作為參數(shù)傳遞給方法。但在Java8之前這實現(xiàn)起來很啰嗦。為接口生命許多只是用一次的實體類而造成的啰嗦代碼,在Java8之前采用匿名類來減少。

      4. JavaAPI包含了很多可以用不同行為進行參數(shù)化的方法,包括排序、線程等。

      代碼示例:

      Github:chap2

      公眾號


        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多