第一章:行为参数化

1.1 应对不断变化的需求:

  有一个 Apple 实体类:

public class Apple {
        private int weight = 0;
        private String color = "";

        public Apple(int weight, String color){
            this.weight = weight;
            this.color = color;
        }

        public Integer getWeight() {
            return weight;
        }

        public void setWeight(Integer weight) {
            this.weight = weight;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public String toString() {
            return "Apple{" +
                   "color='" + color + '\'' +
                   ", weight=" + weight +
                   '}';
        }
    }

构造测试数据:

public static List<Apple> inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red"));

1.1.1 初试牛刀:筛选绿苹果  

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

  如果需求变了,想让你筛选出红苹果,你可以将其copy一下改为filterRedApples方法。可是如果要你筛选更多种颜色的苹果,你会考虑将其抽象化。

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

  如果需求说要你筛选出不同重量的苹果:

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

1.1.3 第三次尝试:对你能想到的每一个属性进行筛选

public static List<Apple> filterApples(List<Apple> inventory, String color, int weight)

1.2 行为参数化:

  定义一个接口来对选择标准建模:

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

  现在你就可以使用不同的实现来代表不同的选择标准了:

static class AppleWeightPredicate implements ApplePredicate{
        public boolean test(Apple apple){
            return apple.getWeight() > 150; 
        }
}

static class AppleColorPredicate implements ApplePredicate{
        public boolean test(Apple apple){
            return "green".equals(apple.getColor());
        }
}

static class AppleRedAndHeavyPredicate implements ApplePredicate{
        public boolean test(Apple apple){
            return "red".equals(apple.getColor()) 
                    && apple.getWeight() > 150; 
        }
}

  第四次尝试:根据抽象条件筛选

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

  传递代码/行为:

static class AppleRedAndHeavyPredicate implements ApplePredicate{
        public boolean test(Apple apple){
            return "red".equals(apple.getColor()) 
                    && apple.getWeight() > 150; 
        }
}

List<Apple> redAndHeavyApples = filterApples(inventory, new AppleRedAndHeavyPredicate());

1.3 对付啰嗦:

  目前,当把把新的行为传入filterApples方法的时候,你不得不声明好几个实现ApplePredicate的接口的实现类,然后实例化只会用的一次的ApplePredicate对象

1.3.1 匿名类,第五次尝试:使用匿名类

List<Apple> redApples2 = filterApples(inventory, new ApplePredicate() {
       public boolean test(Apple a){ return a.getColor().equals("red"); } });

1.3.2 第六次尝试:使用Lambda表达式

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

1.3.3 第七次尝试:将List类型抽象化

  filterApples方法只适用于Apple,你可以将List类型抽象化

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

  这样你家就可以将filter方法应用在苹果,香蕉,Integer或String等各个类型上了

List<Apple> greenApples2 = filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
List<Integer> evenNumber = filter(numbers, (Integer i) -> i % 2 == 0);

1.4 真实的例子

  现在你已经看到了,行为参数化是一个很有用的模式,它可以轻松应对不断变化的需求。这种模式可以把一个行为(一段代码)封装起来,并通过传递和使用创建的行为将方法的行为参数化,这种做法类似于策略设计模式(定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换)。下面看几个例子:

1.4.1 用Comparator来排序:

    在java8中,List自带了一个sort的方法(你可以直接使用Collections.sort)。sort的行为可以用java.util.Comparator对象来参数化,它的方法如下:

public interface Comparator<T> {
    int compare(T o1, T o2);
    ...
}

    因此你可创建不同的实现用sort方法表现出不同的排序行为,比如使用匿名内部类按照重量升序排列:

inventory.sort(new Comparator<Apple>(){
   public int compare(Apple a1, Apple a2){
       return a1.getWeight().compareTo(a2.getWeight());        
   }     
})

    使用Lambda表达式:

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

1.4.2 用Runnable执行代码块:

    创建线程:

Thread t = new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello World");
    }
});

    使用Lambda表达式:

Thread t = new Thread(() -> System.out.println("Hello World"));

 

 

备注:

摘自文献:《Java8实战》(中文版)《Java8 in Action》(英文版)

 

代码(GitHub地址): git@github.com:changlezhong/java8InAction.git

 

posted on 2018-06-02 23:22  changlezhong  阅读(655)  评论(0编辑  收藏  举报

导航