第二章:通过行为参数化传递代码

2018-09-20  本文已影响0人  杨殿生

应对不断变化的需求

行为参数化
可以帮助你处理频繁变更的需求的一种软件开发模式,意味着它拿出一段代码块,准备好确不执行他,这个代码块以后被你程序的其他部分调用,再去执行。推迟这块代码块的执行。

筛选苹果

    //筛选绿色苹果
    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;
    }

第一个版本

把颜色作为参数

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

如果在加上重量呢

    public static List<Apple> filterHeavyApples(List<Apple> inventory,int weight){
        List<Apple> result = new ArrayList<>();
        for (Apple apple:inventory){
            if (apple.getWeight() > weight){
                result.add(apple);
            }
        }
        return result;
    }

这样其实是复制了大量的代码,那么如果不复制代码怎么写呢,那就需要加入一个flag用来区分是按颜色筛选还是用重量筛选


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

这么写出来代码很糟糕,并且如果说我要按大小,形状,产品筛选怎么办?在加入组合筛选又该怎么办?

行为参数化

使用策略模式将策略参数化


策略模式类图.png

定义策略接口

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

分别实现策略

public class AppleGreenColorPredicate implements ApplePredicate{
    @Override
    public boolean test(Apple apple) {
        return apple.getColor().equals("green");
    }
}
public class AppleHeavyWeightPredicate implements ApplePredicate{
    @Override
    public boolean test(Apple apple) {
        return apple.getWeight() > 150;
    }
}

改造筛选方法,将策略传入

    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(lists,new AppleHeavyWeightPredicate());
        filterApples(lists,new AppleGreenColorPredicate());

这样使用策略的方案就好很多了,我们可以创建不同的策略来实现筛选。很灵活

注意我们重要的代码都在下面这句话上,我们必须用对象包裹这段代码才能传入到filterApples中,这种做法类似内联传递代码

return apple.getColor().equals("green");

每次我们都要使用策略我们都要创建一个对象,用来实现策略的接口有没有更简单的方式呢?

匿名类

匿名类可以方便的随用随建,但匿名类还是不够好,他占用了很多空间,同时有些时候他也不是很好理解

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

使用lambda表达式

 filterApples(lists,(Apple apple) -> apple.getColor().equals("yellow"));

将List类型抽象化

之前我们list都是只适用于list,将list参数化,可以处理各种筛选列表问题

    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 t: list){
            if (p.test(t)){}{
                result.add(t);
            }
        }
        return result;
    }

调用

        filter(lists,(Apple apple) -> apple.getColor().equals("yellow"));
        filter(numbers,(Integer i) -> i % 2 == 0);

最终这样就是灵活简洁的代码了

其他应用

用Comparator来排序
给苹果按重量排序

lists.sort((Apple a1,Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

用Runnable执行代码块

new Thread(() -> System.out.println("111"));
上一篇下一篇

猜你喜欢

热点阅读