一、初试牛刀:筛选绿苹果
第一个解决方案多是下面这样的: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 包含不少能够用不一样行为进行参数化的方法,包括排序、线程等。