一、 提出需求
对于程序员来说,唯一不变的需求就是需求永远在变化。你永远不知道,产品经理明天会提出一个怎么样的需求。今天产品经理告诉程序员你:“小吴啊,我们需要完成一个可以筛选出红色苹果的功能。”思考一下,你会如何实现呢?最简单的方法:
public static List<Apple> appleColorFilter(List<Apple> appleList) {
List<Apple> resultList = new ArrayList<>();
for(Apple apple: appleList) {
if(apple.getColor().equals("red")) {
resultList.add(apple);
}
}
return resultList;
}
不费吹灰之力,你就完成了第一个版本的AppleFilter
。就在你上班偷偷摸鱼的时候,产品经理又来了。“小吴啊,我们还需要一个可以筛选出重量大于50g的苹果的功能。”这还不简单?,三下五除二,你又搞定了任务:
public static List<Apple> appleWeightFilter(List<Apple> appleList) {
List<Apple> resultList = new ArrayList<>();
for(Apple apple: appleList) {
if(apple.getWeight() > 50) {
resultList.add(apple);
}
}
return resultList;
}
像上面那样实现,虽然完成了需求,但是两个方法只有一行代码不一样,这样子实现需求,造成代码冗余,而且不容易维护。
二、 将行为参数化
试想一下,如果我们能将筛选苹果这个行为作为一个参数,传递给filterApple()
这个方法,那么一切都要变得简洁得多。我们使用匿名内部类来实现:
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
List<Apple> redApple = appleFilter(apples, new AppleFilterPredicate() {
@Override
public boolean test(Apple apple) {
return apple.getColor().equals("red");
}
});
List<Apple> heavyApple = appleFilter(apples, new AppleFilterPredicate() {
@Override
public boolean test(Apple apple) {
return apple.getWeight() > 50;
}
});
}
public static List<Apple> appleFilter(List<Apple> appleList, AppleFilterPredicate predicate) {
List<Apple> resultList = new ArrayList<>();
for (Apple apple: appleList) {
if(predicate.test(apple)) {
resultList.add(apple);
}
}
return resultList;
}
我们通过将行为参数化,即把如何筛选苹果作为参数,传递给appleFilter()
。这样子做,让我们能够将筛选苹果与遍历苹果这个两个行为分离出来。这样子让我们的代码易于管理,但冗余的问题并没有完全解决。
三、lambda表达式
上面的匿名内部类,其实可以使用lambda简写为:
List<Apple> redApple = appleFilter(apples, apple->apple.getColor().equals("red"));
是不是看起来很简洁。初次看lambda可能会有点难以理解,关于lambda的具体的使用,我们后面再聊。