【Java 8】行为参数化

来源:互联网 发布:ug编程二次开粗技巧 编辑:程序博客网 时间:2024/05/20 07:37

【Java 8】行为参数化

行为参数化——Lambda表达式之前

行为参数化,就是可以帮助你处理频繁变更的需求的一种软件开发模式。

行为参数化,旨在抽象出具有某种功能的代码(它的输入参数和返回值是固定的),以某种方式将此代码传入到其他的方法中,以辅助它们的操作。

行为参数化之前

应对不断变化的需求的一个例子——选苹果
其中,苹果的定义如下:

    private class Apple{        private int weight;        private String color;        // constructor, setter, getter    }

需求一:挑选出集合中的青苹果或者红苹果
我们可以非常容易的想到下面的方法,在挑选的方法参数列表中加上color条件,
遍历集合,如果当前苹果的颜色跟指定颜色相等,则加入到表示结果的集合中。
方案:

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

需求二:挑选出集合中重量大于200的苹果
和需求一的解决方案类似,在挑选的方法参数列表中加上weight参数,
遍历集合,如果当前苹果的重量大于weight,则加入到表示结果的集合中。

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

……
需求N:挑选重量在100~200之间的红色苹果。
此时,如果按照上面的方法,需要不断地实现挑选苹果的方法。
怎么简化开发呢?其实,上面的方法各不相同,但是他们有一个共同点,就是选择苹果时,需要一个标准,满足这个标准则挑选出来,否则,跳过。很明显,这个标准可以定义为只有两种返回值的布尔类型的方法。如果能够定义这样的标准,并把它们传递给挑选方法,我们通过一个挑选方法就可以挑选满足各种条件的苹果。
那么,怎么实现这个想法呢?

答案是,通过对象传递方法。

行为参数化

我们先定义一个接口,这个接口只有一个抽象方法,传递给它一个苹果,它返回boolean类型的结果。
当前不需要关心这个抽象方法的方法体的具体判断内容是什么。首要任务是,能把这个方法传递给挑选苹果的方法中。

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

此时,我们在挑选苹果的方法中调用这个挑选条件

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

predicate.test(apple) 成功地嵌入到挑选苹果的方法中了

以后,我们再挑选苹果,只需要把实现ApplePredicate接口,覆写predicate.test(apple)方法,把实现类的实例传递给挑选苹果的方法就可以选择满足条件的苹果,我们不需要多次写挑选苹果的代码。

比如,我们要挑选出青苹果,首先实现覆写test方法,然后将接口的实例传递给挑选苹果的方法即可。

 class AppleColorPredicate implements ApplePredicate{     @Override     public boolean test(Apple apple) {         return "green".equals(apple.getColor());     } } List<Apple> result = filterApplesByPredicate(appleList, new AppleColorPredicate());

同样,我们以可以选择重量在160一下的苹果

 class AppleWeightPredicate implements ApplePredicate{     @Override     public boolean test(Apple apple) {         return apple.getWeight() < 160;     } }List<Apple> result = filterApplesByPredicate(appleList, new AppleWeightPredicate())

至此,我们以可以不用重复编写挑选苹果的方法,只需要覆写挑选条件方法即可,这比行为参数化之间简化了代码量。
但是,这也有一个很大的弊端,随着挑选条件的变化,我们需要不停地创建新的实现了指定接口的类。
一个好主意是,使用匿名类。
比如,挑选出重量小于200的绿苹果。

 public void filterApplesByAnonymousPredicate(){     List<Apple> result = filterApplesByPredicate(appleList, new ApplePredicate(){         @Override         public boolean test(Apple apple) {             return "green".equals(apple.getColor())                     && apple.getWeight() < 200;         }     }); }

以上,行为参数化的本质,是通过传递对象实现传递方法(方法属于某个对象)
不停地实现这个指定的接口并不能使人满意,代码还可以再简化吗?
在Java8之前,没有什么更好的办法了。
好在,Java8为我们提供了更加简便、更加优雅的实现方式——Lambda表达式。

初探Lambda表达式

如果和行为参数中一样,我们定义了只含有一个抽象方法的接口和挑选苹果的方法,如下:

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

使用Lambda表达式挑选红苹果和挑选出重量小于160的苹果的代码如下:

 List<Apple> result = filterApplesByPredicate(appleList,                          (Apple apple) -> "red".equals(apple.getColor())); ApplePredicate weigthPredicate = (Apple apple) -> apple.getWeight() < 160; List<Apple> result02 = filterApplesByPredicate(appleList, weigthPredicate);

此时,代码变得如此简洁,让人觉得不可思议。
Java8,good job。

不过,初次见面,为何觉得Lambda表达式如此奇怪?下一节,将详细介绍Lambda表达式。

参考:《Java 8 in action》

原创粉丝点击