java1.8实战学习(五)——通过行为参数化传递代码

版权声明:转载请附上博客地址谢谢 https://blog.csdn.net/F_QWERDF/article/details/84840451

上一篇:java1.8实战学习(四)——通过行为参数化传递代码

下一篇:

上节答案:

首先,你需要一种表示接受Apple并返回一个格式String值的方法。前面我们在编写ApplePredicate接口的时候,写过类似的东西:
 

public interface AppleFormatter{ 
 String accept(Apple a); 
} 

现在你就可以通过实现AppleFormatter方法,来表示多种格式行为了:

public class AppleFancyFormatter implements AppleFormatter{ 
 public String accept(Apple apple){ 
 String characteristic = apple.getWeight() > 150 ? "heavy" : 
 "light"; 
 return "A " + characteristic + 
 " " + apple.getColor() +" apple"; 
 } 
} 
public class AppleSimpleFormatter implements AppleFormatter{ 
 public String accept(Apple apple){ 
 return "An apple of " + apple.getWeight() + "g"; 
 } 
} 

最后,你需要告诉prettyPrintApple方法接受AppleFormatter对象,并在内部使用它们。你可以给prettyPrintApple加上一个参数:

public static void prettyPrintApple(List<Apple> inventory, 
 AppleFormatter formatter){ 
 for(Apple apple: inventory){ 
 String output = formatter.accept(apple); 
 System.out.println(output); 
 } 
} 

现在你就可以给prettyPrintApple方法传递多种行为了。为此,你首先要实例化AppleFormatter的实现,然后把它们作为参数传给prettyPrintApple:

prettyPrintApple(inventory, new AppleFancyFormatter()); 


这将产生一个类似于下面的输出:
A light green apple 
A heavy red apple 
… 
或者试试这个:

prettyPrintApple(inventory, new AppleSimpleFormatter()); 


这将产生一个类似于下面的输出:
An apple of 80g 
An apple of 155g 

你已经看到,可以把行为抽象出来,让你的代码适应需求的变化,但这个过程很啰嗦,因为你需要声明很多只要实例化一次的类。让我们来看看可以怎样改进。

对付啰嗦

public class AppleHeavyWeightPredicate implements ApplePredicate{ 
 public boolean test(Apple apple){ 
 return apple.getWeight() > 150; 
 } 
} 
public class AppleGreenColorPredicate implements ApplePredicate{ 
 public boolean test(Apple apple){ 
 return "green".equals(apple.getColor()); 
 } 
} 
public class FilteringApples{ 
 public static void main(String...args){ 
 List<Apple> inventory = Arrays.asList(new Apple(80,"green"), 
 new Apple(155, "green"), 
 new Apple(120, "red")); 
 List<Apple> heavyApples = 
 filterApples(inventory, new AppleHeavyWeightPredicate()); 
 List<Apple> greenApples = 
 filterApples(inventory, new AppleGreenColorPredicate()); 
 } 
 public static List<Apple> filterApples(List<Apple> inventory, 
 ApplePredicate p) { 
 List<Apple> result = new ArrayList<>(); 
 for (Apple apple : inventory){ 
 if (p.test(apple)){ 
 result.add(apple); 
 } 
 } 
 return result; 
 } 
} 

费这么大劲儿真没必要,能不能做得更好呢?Java有一个机制称为匿名类,它可以让你同时声明和实例化一个类。 

第五次尝试:使用匿名类

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

但匿名类还是不够好。第一,它往往很笨重,因为它占用了很多空间。第二,很多程序员觉得它用起来很让人费解。

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

上面的代码在Java 8里可以用Lambda表达式重写为下面的样子:

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

它看起来更像问题陈述本身了。我们现在已经解决了啰嗦的问题。

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

在通往抽象的路上,我们还可以更进一步。目前,filterApples方法还只适用于Apple。你还可以将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 e: list){ 
 if(p.test(e)){ 
 result.add(e); 
 } 
 } 
 return result; 
} 

现在你可以把filter方法用在香蕉、桔子、Integer或是String的列表上了。这里有一个使用Lambda表达式的例子:

List<Apple> redApples = 
 filter(inventory, (Apple apple) -> "red".equals(apple.getColor())); 
List<Integer> evenNumbers = 
 filter(numbers, (Integer i) -> i % 2 == 0); 

你现在在灵活性和简洁性之间找到了最佳平衡点,这在Java 8之前是不可能做到的!

 

猜你喜欢

转载自blog.csdn.net/F_QWERDF/article/details/84840451