0x01:策略模式简介
策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要交个人所得税,但是根据个人的收入情况,个人所得税的计算算法是有不同的策略的。
我想大家都看过《三国演义》,其中刘备娶孙夫人时,诸葛亮交给赵云三个
锦囊,就是三个策略
锦囊一:到达东吴,先去拜会乔国老
锦囊二:刘备贪念美色不思离开,就对他谎称曹操大军压境
锦囊三:如果被东吴军队追赶,求孙夫人解围
策略模式的UML类图如下:
主要角色分析:
抽象策略角色(Strategy): 策略类,通常由一个接口或者抽象类实现;
具体策略角色(ConcreteStrategyA):包装了相关的算法和行为;
上下文角色(Context):持有一个策略类的引用,最终给客户端调用;
Context是上下文,用一个ConcreteStrategy来配置,维护一个Strategy对象的引用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。
0x02:策略模式实现
Context:Context上下文角色,也叫Context封装角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
//上下文接口
public void contextInterface(){
strategy.algorithmInterface();
}
}
Strategy:抽象策略角色,是对策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。algorithm是运算法则的意思。
public abstract class Strategy {
//算法方法
public abstract void algorithmInterface();
}
ConcreteStrategy:具体策略角色,用于实现抽象策略中的操作,即实现具体的算法,下方用print代替。
public class ConcreteStrategyA extends Strategy{
@Override
public void algorithmInterface(){
System.out.println("ConcreteStrategyA 实现");
}
}
public class ConcreteStrategyB extends Strategy{
@Override
public void algorithmInterface(){
System.out.println("ConcreteStrategyB 实现");
}
}
public class ConcreteStrategyC extends Strategy{
@Override
public void algorithmInterface(){
System.out.println("ConcreteStrategyC 实现");
}
}
策略模式测试代码:可以依次更换策略,测试一下策略模式。
public class Client{
public static void main(String[] args){
Context context = null;
context = new Context(new ConcreteStrategyA());
context.contextInterface();
context = new Context(new ConcreteStrategyB());
context.contextInterface();
context = new Context(new ConcreteStrategyC());
context.contextInterface();
}
}
0x03:策略模式在JDK的运用
在多线程编程中,经常使用线程池来管理线程,以减缓线程频繁的创建和销毁带来的资源的浪费,其中ThreadPoolExecutor类中的RejectedExecutionHandler参数就是一个使用了策略模式的典型例子。
ThreadPoolExecutor的构造函数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler){
if (corePoolSize
maximumPoolSize <= 0 ||
maximumPoolSize
keepAliveTime
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
RejectedExecutionHandler接口
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
RejectedExecutionHandler的四种策略实现
CallerRunsPolicy:该策略并没有抛弃任何的任务,由于线程池中已经没有了多余的线程来分配该任务,该策略是在当前线程(调用者线程)中直接执行该任务;
AbortPolicy:该策略是直接将提交的任务抛弃掉,并抛出RejectedExecutionException异常;
DiscardPolicy:该策略也是将任务抛弃掉(对于提交的任务不管不问,什么也不做),不过并不抛出异常。
DiscardOldestPolicy:该策略是当执行器未关闭时,从任务队列workQueue中取出第一个任务,并抛弃这第一个任务,进而有空间存储刚刚提交的任务。使用该策略需要特别小心,因为它会直接抛弃之前的任务。
public static class CallerRunsPolicy implements RejectedExecutionHandler{
public CallerRunsPolicy(){ }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e){
if (!e.isShutdown()) {
r.run();
}
}
}
public static class AbortPolicy implements RejectedExecutionHandler{
public AbortPolicy(){ }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e){
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
public static class DiscardPolicy implements RejectedExecutionHandler{
public DiscardPolicy(){ }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e){
}
}
public static class DiscardOldestPolicy implements RejectedExecutionHandler{
public DiscardOldestPolicy(){ }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e){
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}