策略模式:定义了算法族
,分别封装起来,让算法族下的算法之间可以被替换。策略模式将算法独立于使用算法的客户之外。
其实我们已经学会了策略模式了。在上一篇最后使用的其实就是策略模式。回去翻一下会发现,我们把鸭子的行为(算法族)封装起来,给行为具体实现(算法)。组合行为(算法族)到鸭子上实现动态可以动态改变行为(算法)。这不就是策略模式吗。本篇我们找个实际应用到的例子。
JDK8的java.util.function包下提供了一系列算法族。其实接口Supplier、Predicate、Consumer、Function这些我们在学习jdk8特性的时候会接触到。因为jdk8最大一个设计就是函数式编程了。其实其中就大量用到了策略模式。只不过不同的是,我们之前是提前将实现写好放到一个类里面,这里是直接匿名实现。当成参数传递下去。这一系列接口出来之后,感觉没有比这些更简单的策略模式实例了。简直一目了然。
最简单的例子:Consumer
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
我们看到Consumer接口写了两个方法。一个是accept另一个是andThen。其中andThen已经提供了默认实现。而accept则没有。因此该接口的子类是都要要求实现accept方法的。该接口定义了一个Consumer算法族。接收一个T类型的参数t,并实现自定义逻辑。
最简单明了的使用
public class DemoTest {
@Test
public void test() {
//定义五个策略:每个策略实现一个算法
Consumer<String> strategy1 = o -> System.out.println("算法1:" + o);
Consumer<String> strategy2 = o -> System.out.println("算法2:" + o);
Consumer<String> strategy3 = o -> System.out.println("算法3:" + o);
Consumer<String> strategy4 = o -> System.out.println("算法4:" + o);
Consumer<String> strategy5 = o -> System.out.println("算法5:" + o);
//执行算法
strategy1.accept("参数1");
strategy2.accept("参数2");
strategy3.accept("参数3");
strategy4.accept("参数4");
strategy5.accept("参数5");
}
}
可以说代码是很清晰了,定义了五个策略实现每个策略的算法,然后执行。如果没有这么写过代码没关系。看下面这段。
public class DemoTest {
@Test
public void test() {
strategy(t -> System.out.println("算法" + t + ":参数" + t),"1");
strategy(t -> System.out.println("算法" + t + ":参数" + t),"2");
strategy(t -> System.out.println("算法" + t + ":参数" + t),"3");
strategy(t -> System.out.println("算法" + t + ":参数" + t),"4");
strategy(t -> System.out.println("算法" + t + ":参数" + t),"5");
}
/**
* 策略
* @param consumer
* @param t
* @param <T>
*/
public <T> void strategy(Consumer<T> consumer,T t) {
consumer.accept(t);
}
}
定义了一个参数类型为Consumer算法族接口,在待用的的时候传入实现(算法),并传入需要的参数。这就形成了一个策略。然后该接口调用方法accept去执行策略。整个策略模式的核心就是将动态实现算法族的算法,抽象的不是参数,而是实现和算法。是不是很简单。没有复杂的UML,没有一大堆类。实际应用就这么简单就可以使用了。简直没有比这跟简单的策略模式案例了。