行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式。一言以弊之,它意味着拿出一个代码块,把它准备好却不去执行它。这个代码块以后可以被你的程序的其他部分调用,这意味着你可以推迟这块代码的执行。
一、应对不断变化的需求
1、初试牛刀:筛选绿苹果
public static ListfilterGreenApples(List inventory){ List result = new ArrayList<>(); for(Apple apple: inventory){ if("green".equals(apple.getColor())){ result.add(apple); } }
2、再展身手:把颜色作为参数
public static ListfilterApplesByColor(List inventory, String color){ List result = new ArrayList<>(); for(Apple apple: inventory){ if(apple.getColor().equals(color)){ result.add(apple); } } return result;}
3、第三次尝试:对你能想到的每个属性做筛选
public static ListfilterApplesByColor(List inventory, String color,int weight,boolean flag){ List result = new ArrayList<>(); for(Apple apple: inventory){ if((flag &&apple.getColor().equals(color))|| (!flag &&apple.getWeight()>weight)){ result.add(apple); } } return result;}
二、行为参数化
1、定义一个接口来对选择标准建模(即定义一族算法),把它们封装起来(称为“策略”),然后再运行时选择一个算法。
2、参数化:让方法接收多种行为(或战略)作为参数,并在内部使用,来完成不同的行为。
3、第四次尝试:根据抽象条件筛选
(1)传递代码行为
public static ListfilterApples(List inventory, Predicate p){ List result = new ArrayList<>(); for(Apple apple : inventory){ if(p.test(apple)){ result.add(apple); } } return result;}
注: 正是test方法定义了filterApples方法的新行为,但令人遗憾的是,由于filterApples方法只能接收对象,所以你必须把代码包裹在ApplePredicate对象里。你的做法就类似于在内联“传递代码”,因为你是通过实现了test方法的对象来传递布尔表达式的。
(2)多种行为,一个参数 正如我们先前解释的那样,行为参数化的好处在于你可以把迭代要筛选的集合逻辑与对集合中每个元素应用的行为区分开来。
三、对付啰嗦
1、匿名类
2、第五次尝试:使用匿名类
ListredApples2 = filter(inventory, new ApplePredicate() { public boolean test(Apple a){ return a.getColor().equals("red"); } }); System.out.println(redApples2);}
3、第六次尝试:使用Lambda表达式
Listresult = filterApples(inventory,(Apple apple)) -> "red".equles(apple.getColor())
4、第七次尝试:将List类型抽象化
public staticList filter(List list,Predicate p){ List result = new ArrayList<>(); for(T e : list){ if(p.test(e)){ result.add(e); } } return result;}