在實際的工做中咱們會將現實問題抽象成對象並對其進行處理,好比須要對一堆顏色和重量不一樣的蘋果進行過濾分類。java
一、蘋果實體類算法
public class Apple { // 顏色 private String color; // 重量 private Integer weight; // Getter and Setter }
二、過濾方法設計模式
public static List<Apple> filter(List<Apple> appleList, String color, int weight) { // 符合條件的蘋果集合 List<Apple> result = new ArrayList<>(); for (Apple apple : appleList) { // 若是顏色和重量符合條件就存入 if (color.equalsIgnoreCase(apple.getColor()) && weight == apple.getWeight()) { result.add(apple); } } return result; }
經過定製過濾方法,好比後期蘋果可能會有其餘的屬性,是否成熟、產地等。咱們能夠在過濾方法的入參加上對應的屬性並在內部進行判斷。這就是經過修改過濾方法來 應對不斷變化的需求
。但這樣有其侷限性,若是需求不斷地更改,那麼就須要重寫不少類似的方法。這違背了app
DRY(Don't Repeat Yourself)ide
的軟件工程原則。設計
咱們其實能夠經過標準建模來定義一個過濾接口,讓其比重寫不少次過濾方法更好地 應對不斷變化的需求
。code
一、創建蘋果謂詞接口對象
// predicate:謂詞,即一個返回 boolean 值的接口 public interface ApplePredicate { boolean test(Apple apple); }
二、運用策略模式思想來構建具體算法(策略)實現接口
public class AppleColorPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { // 選出綠色的蘋果 return "green".equalsIgnoreCase(apple.getColor()); } } public class AppleWeightPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { // 選出重量大於1的蘋果 return 1 < apple.getWeight(); } }
策略模式做爲一種軟件設計模式,指對象有某個行爲,可是在不一樣的場景中,該行爲有不一樣的實現算法。ip
- 定義了一族算法(業務規則);
- 封裝了每一個算法;
- 這族的算法可互換代替(interchangeable)—— 策略模式 - 維基百科,自由的百科全書
咱們能夠將 AppleColorPredicate
和 AppleWeightPredicate
看做是 過濾方法
的不一樣行爲,須要 過濾方法
接收 ApplePredicate
對象對蘋果進行過濾。這就是 行爲參數化
:讓方法接收多種行爲(或策略)做爲參數,並在內部使用,來完成不一樣的行爲。
一、修改過濾方法讓其可以接收蘋果謂詞接口對象
public static List<Apple> filter(List<Apple> appleList, ApplePredicate applePredicate) { // 符合條件的蘋果集合 List<Apple> result = new ArrayList<>(); for (Apple apple : appleList) { // 若是符合條件就存入 if (applePredicate.test(apple)) { result.add(apple); } } return result; }
二、調用過濾方法進行過濾
public class Main { public static void main(String[] args) { List<Apple> appleList = new ArrayList<>(); Apple apple = new Apple(); apple.setColor("red"); apple.setWeight(1); appleList.add(apple); apple = new Apple(); apple.setColor("green"); apple.setWeight(2); appleList.add(apple); List<Apple> result = filter(appleList, new AppleWeightPredicate()); } }
result 中就會只有重量大於1的蘋果集合了。行爲參數化
的好處在於咱們能夠把過濾的邏輯 boolean test()
與應用過濾的行爲 public static List<Apple> filter()
解耦。這樣在需求不斷更改時,只須要新增 ApplePredicate
實現再調用就行。
然而按照以上方式使用 ApplePredicate
依然有一個問題,那就是咱們仍是得不斷地新增 ApplePredicate
的實現。本質上只是把重寫過濾方法的代價轉移到了新增謂詞實現上。這個時候咱們能夠換一個思路出發,使用 匿名類
來隨用隨建謂詞實現。
使用匿名類實現謂詞接口
List<Apple> result = filter(appleList, new ApplePredicate() { @Override public boolean test(Apple apple) { // 選出綠蘋果且重量爲2 return "green".equalsIgnoreCase(apple.getColor()) && 2 == apple.getWeight(); } });
如今,咱們只須要每次去匿名實現謂詞接口就行,然而這樣的寫讓人以爲很臃腫,並且看起來很讓人費解。接下來看看 Lambda 是怎麼讓其變得簡潔又友好的。
經過 Lambda 簡化匿名實現
List<Apple> result = filter(appleList, (Apple apple1) -> "green".equalsIgnoreCase(apple1.getColor()) && 2 == apple1.getWeight());
是否是簡潔得有點看不懂了?不要緊,先細細品味,下一章咱們會詳細瞭解 Lambda。
咱們還能夠進一步抽象。目前 ApplePredicate
還只適用於蘋果,而我想要其餘對象進行過濾呢?可使用泛型來定義須要處理的對象。
一、修改 ApplePredicate 成 Predicate
public interface Predicate<T> { boolean test(T t); }
二、修改過濾方法
public static <T> List<T> filter(List<T> list, Predicate<T> predicate) { // 符合條件的集合 List<T> result = new ArrayList<>(); for (T t : list) { // 若是符合條件就存入 if (predicate.test(t)) { result.add(t); } } return result; }
這樣咱們就能將過濾方法用在其餘對象上了。下一章咱們會更加深刻地理解 Lambda 是什麼,能幹什麼。
Java 8 實戰 第二章 經過行爲參數化傳遞代碼 讀書筆記
這是我第一篇文章,歡迎加入咖啡館的春天(338147322)。