第二章:通过行为参数化传递代码
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"));