1-通过行为参数化传递代码-Java8

通过行为参数化传递代码

不管你做什么,用户的需求肯定会变。

之前

​ 有个果农对自己的果园里的苹果采摘下来了,他想要对自己的苹果进行一个过滤,查找出所有颜色为绿色的苹果

​ 我们可以很轻易的编写出一个简单的程序进行实现。

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

​ 当需求更改,需要筛选为红色的苹果时,我们可能会想到复制这个方法,改个方法名filterRedApples,如果后续需要橙色、暗红色等。这个显而易见不太够了,我们需要进行一层复用。(并没有对参数等进行判空操作!)

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

​ 但是,筛选条件变成重量,又要怎么操作?难道新编写个方法filterApplesByWeight?显然不太行。你可能会把属性作为参数进行方法的封装,比如:

public static List<Apple> filterApples(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;
}

​ 不提代码看起来很丑陋,后续如果条件更加复杂,那这个代码无论是写还是读,都是一个巨大的灾难!

之后

​ 我们将之前的思路继续进行抽象,我们针对的过滤操作,无论是基于颜色、重量都是苹果的,因此我们可以针对苹果的某些属性进行封装,返回一个boolean,这称之为Predicate(谓词)

public interface ApplePredicate {

    boolean test(Apple apple);

}

​ 我们可以通过继承ApplePredicate来实现对不同的苹果进行筛选的操作了。

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

​ 这些操作和策略设计模式相关。

​ 怎么利用ApplePredicate的不同实现呢?你需要filterApples方法接受ApplePredicate对象,对Apple做条件测试。这就是行为参数化:让方法接受多种行为(或战略)作为参数,并在内部使用,来完成不同的行为。

public static List<Apple> filterApples(List<Apple> inventory,
                                       ApplePredicate predicate) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple : inventory) {
        if (predicate.test(apple)) {
            result.add(apple);
        }
    }
    return result;
}

​ 至此,filterApples方法的行为取决于你通过ApplePredicate对象传递的代码。换句话说,我们把filterApples方法的行为参数化了。目前我们的filterApples方法仅接收了一个对象作为入参,后续我们可以通过更加简洁的方式完成这个操作。

​ 上述的代码缺点在于类过于冗余,我们可能仅仅使用AppleHeavyWeightPredicate一次,但是必须要进行一次类的继承与实例化。

​ JAVA为我们提供了匿名函数,可以让这些代码稍微优雅一些。

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

​ 但是匿名函数还是不够简洁,当我们需要通过重量进行筛选时。

List<Apple> apples = filterApples(inventory, new ApplePredicate() {
    @Override
    public boolean test(Apple apple) {
        return apple.getWeight()>150;
    }
});

​ 甚至某些时候,匿名函数可能会让人感到费解。

​ JAVA8出现了Lambda,我们可以使用Lambda重写代码成:

List<Apple> apples = filterApples(inventory, 
                                  (Apple apple) -> "green".equals(apple.getColor()));

​ 到现在,代码已经变得非常优雅了,但我们从ApplePredicate这个接口的命名来看,我们就知道,代码的抽象及复用度不够。它目前仅仅适用于Apple,我们可以对它进行再抽象。

public interface Predicate<T> {

    boolean test(T t);

}

​ 我们通过这个接口,把filter方法运用到任何我们想要运用到的地方了!

行为参数化值参数化的区别。值参数化过于死板,无论是从复用方面还是优美程度,都比不上行为参数化,行为参数化可以轻松适应不断变化的需求。

多种行为,一个参数!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值