Java8之行为参数化

概念       

在软件开发中,最常见的就是需求变更。比如说,有个程序帮助农民了解自己的库存,第一天农民想知道库存中绿色的苹果有多少个,你写好了代码,但第二天,农民想知道自己的库存中有多少重量大于150克的,这次你有修改好了代码,之后农民又想知道绿色的和重量大于150克的苹果有多少。就这要你需要修改多次你所写的程序。理想的状态下,应该把你的工作量降到最少。此外,类似的新功能实现起来还应该很简单,而且易于长期维护。

行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式。例子和code是比较好理解的。

结合例子讲解

现在我们就结合上面农民的例子讲解下。

1.初试牛刀:筛选绿苹果

一般代码会这样写:

public static List<Apple> filterGreenApples(List<Apple> inventory) {
        List<Apple> result = new ArrayList<>();
        for (Apple a : inventory){
            if ("green".equals(a.getColor())){
                result.add(a);
            }
        }
        return result;
    }

如果农民想要不同颜色的苹果数量,创建多个方法是不好的,我们可以将其抽象起来。

2.把颜色作为参数

public static List<Apple> filterApplesByColor(List<Apple> inventory,
                                                  String color) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple: inventory){
            if ( apple.getColor().equals(color) ) {
                result.add(apple);
            }
        }
        return result;
    }

这样看起来不错了(错觉哦!),农民想要什么颜色都有了,但是我们之前的例子中,农民想知道重量大于150克的有多少。根据上个我们一般会想再写一个类似上面的方法,但这样就违背了“Don`t repeat yourself”的软件原则。我们可以尝试笨一点的方法,但绝对不要这样做(巨丑,只供辣眼睛!!!)

3.巨丑的尝试

public static List<Apple> filterApples(List<Apple> inventory, String color,
                                       int weight, boolean flag) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple: inventory){
        boolean isFlag = (flag && apple.getColor().equals(color)) ||
                (!flag && apple.getWeight() > weight);
        if (isFlag){
            result.add(apple);
        }
    }
    return result;
}

这个解决方案再差不过了。首先,客户端代码看上去糟透了。 true 和 false 是什么意思?此
外,这个解决方案还是不能很好地应对变化的需求。如果这位农民要求你对苹果的不同属性做筛
选,比如大小、形状、产地等,又怎么办?而且,如果农民要求你组合属性,做更复杂的查询,
比如绿色的重苹果,又该怎么办?你会有好多个重复的 filter 方法,或一个巨大的非常复杂的
方法。到目前为止,你已经给 filterApples 方法加上了值(比如 String 、 Integer 或 boolean )

的参数。

4.行为参数化

一种可能的解决方案是对你的选择标准建模:你考虑的
是苹果,需要根据 Apple 的某些属性(比如它是绿色的吗?重量超过150克吗?)来返回一个
boolean 值。我们把它称为谓词(即一个返回 boolean 值的函数)。让我们定义一个接口来对选
择标准建模:

public interface ApplePredicate {
    boolean test(Apple apple);
}

现在你就可以用 ApplePredicate 的多个实现代表不同的选择标准了,比如:

public class AppleHeavyWeightPredicate implements ApplePredicate {
    @Override
    public boolean test(Apple apple) {
        return apple.getWeight() > 150;
    }
}
public class AppleGreenColorPredicate implements ApplePredicate {
    @Override
    public boolean test(Apple apple) {
        return "green".equals(apple.getColor());
    }
}
这个就是典型的“策略模式”,不同的策略就是 AppleHeavyWeightPredicate 和 AppleGreen-
ColorPredicate 。
但是,该怎么利用 ApplePredicate 的不同实现呢?你需要 filterApples 方法接受
ApplePredicate 对象,对 Apple 做条件测试。这就是行为参数化:让方法接受多种行为(或战

略)作为参数,并在内部使用,来完成不同的行为。

添加谓语后方法应该是这样的:

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;
}

对于这样我们一般会这样写:

List<Apple> inventory = Arrays.asList(new Apple("red", 156),
        new Apple("green",112));
List<Apple> greenApples = filterApples(inventory, new AppleGreenColorPredicate());
List<Apple> heavyApples = filterApples(inventory, new AppleHeavyWeightPredicate()); 

但是这样很费劲,能不能写的更好呢?

使用匿名类:

filterApples(inventory, new ApplePredicate() {
    @Override
    public boolean test(Apple apple) {
        return "green".equals(apple.getColor());
    }
});

这样是不是更好了,那还能不能更好呢?

使用Lambda:

filterApples(inventory, apple -> "green".equals(apple.getColor()));

这样是不是更好了,声明的实现类也少了,方法更通用了,也不怕修改需求了,但是现在农民种的是西瓜呢或者其他水果,这个方法又不通用了,所以我们可以做的更好。

抽象传入的参数:

public interface Predicate<T>{
    boolean test(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;
}

这样筛选方法就很通用了,这里只是个例子,在Java8中已经有了filter方法,目的就是本次讲的这样,适用于各种对象数组的筛选。

总结

在Java8中大量使用了行为参数化,这样一个方法就更加通用了,接受多个不同行为的参数,在内部使用,完成不同的行为。

大家可以好好读读《Java8实践》这本书,网上有电子中文版的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值