经过行为参数化传递代码

应对不断变化的需求

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

咱们能够将 AppleColorPredicateAppleWeightPredicate 看做是 过滤方法 的不一样行为,须要 过滤方法 接收 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)。

相关文章
相关标签/搜索