在实际的工做中咱们会将现实问题抽象成对象并对其进行处理,好比须要对一堆颜色和重量不一样的苹果进行过滤分类。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)。