一、初試牛刀:篩選綠蘋果
第一個解決方案多是下面這樣的:java
public static List<Apple> filterGreenApples(List<Apple> inventory){ List<Apple> result=new ArrayList<>(); //僅僅篩選出綠蘋果 for (Apple apple : inventory) { if ("green".equals(apple.getColor())){ result.add(apple); } } return result; }
上面代碼只針對綠蘋果進行篩選,如今,我還想篩選出紅蘋果,該怎麼作呢?簡單的解決辦法就是重複寫一個方法,再改條件爲紅蘋果,可是,要篩選的顏色有多種的狀況,這樣寫會致使代碼十分冗餘,因此咱們第一步嘗試將其抽象化。算法
二、再展身手:把顏色做爲參數
public static List<Apple> filterGreenApples(List<Apple> inventory,String color){ List<Apple> result=new ArrayList<>(); //顏色做爲參數 for (Apple apple : inventory) { if (color.equals(apple.getColor())){ result.add(apple); } } return result; }
可是如今又想根據蘋果的重量對蘋果進行篩選,那是否是也要用另一個參數表示蘋果重量呢?以後我又想加個標誌區分對顏色和重量的查詢呢?下面是展現通常寫法,可是很傻。設計模式
三、第三次嘗試:對你能想到的每一個屬性作篩選
public static List<Apple> filterGreenApples(List<Apple> inventory,String color,int weight,boolean flag){ List<Apple> result=new ArrayList<>(); for (Apple apple : inventory) { if (flag && color.equals(apple.getColor())|| (!flag && apple.getWeight()>weight)){ result.add(apple); } } return result; }
四、柳暗花明:行爲參數化
咱們能夠把行爲進行參數化,來達到更高層次的抽象,首先定義一個統一的標準接口,再經過不一樣子類對其進行實現,這有點相似於策略設計模式的趕腳。app
//封裝了對選擇蘋果的策略 public interface ApplePredicate { //具體算法交給子類去實現 boolean test (Apple apple); }
//顏色算法 public class AppleGreenColorPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return "green".equals(apple.getColor()); } } //重量算法 public class AppleHeavyWeightPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return apple.getWeight()>150; } }
五、第四次嘗試:根據抽象條件篩選
public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate p){ List<Apple> result = new ArrayList<>(); //行爲參數化 for (Apple apple : inventory) { if (p.test(apple)){ result.add(apple); } } return result; }
咱們在使用的時候能夠傳遞不一樣的策略實現來達到目的ide
List<Apple> heavyApples = filterApples(inventory, new AppleHeavyWeightPredicate()); List<Apple> greenApples = filterApples(inventory, new AppleGreenColorPredicate());
可是這樣有個問題,就是每一個策略我都要定義一個實現類去實現某個算法,致使後面若是有不少策略,會增長不少的類,咱們知道使用匿名類也是一種不錯的選擇spa
六、第五次嘗試:使用匿名類
List<Apple> redApples = filterApples(inventory, new ApplePredicate() { @Override public boolean test(Apple apple){ return "red".equals(apple.getColor()); } });
可是問題又來了,匿名類仍是不夠好,第一,它每每很笨重,佔用了不少的空間,第二,使用起來讓人費解,致使代碼可讀性不高,即便匿名類處理在某種程度上改善了爲一個接口聲明好幾個實體類的囉嗦問題,可是仍是不能使人滿意,自java8引入的lambda表達式——一種更簡潔的傳遞代碼的方式解決了這個問題。下面咱們利用lambda表達式來改寫前面的代碼吧線程
七、第六次嘗試:使用Lambda表達式
List<Apple>result= filterApples(inventory, (Apple apple)-> "red".equals(apple.getColor()));
不得不認可,使用lambda表達式改寫以前的代碼確實乾淨不少,由於它看起來更像問題陳訴自己了,解決了囉嗦的問題設計
八、第七次嘗試:將List類型抽象化
在通往抽象的路上,咱們還能夠進一步。目前filterApples方法還只適用Apple,咱們還能夠嘗試適用在其餘水果上。code
public interface Predicate<T> { boolean test(T t); }
//映入類型參數T 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; }
如今你能夠吧filter方法做用在橘子,香蕉等列表上了。排序
九、小結
行爲參數化,就是一個方法接收不一樣的行爲做爲參數,並在內部使用他們,完成不一樣行爲的能力。
行爲參數化可讓代碼更好的適應不斷變化的要求,減輕將來的工做量。
傳遞代碼,就是將新行爲做爲參數傳遞給方法,可是在java8以前實現起來很囉嗦。爲接口聲明許多隻用一次的實體類而形成的囉嗦代碼,在java8以前能夠用匿名類來減小。
java API 包含不少能夠用不一樣行爲進行參數化的方法,包括排序、線程等。