0
点赞
收藏
分享

微信扫一扫

你有张良计,我有过墙梯之策略模式


你有张良计,我有过墙梯之策略模式_并发编程

0x01:策略模式简介

策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要交个人所得税,但是根据个人的收入情况,个人所得税的计算算法是有不同的策略的。

我想大家都看过《三国演义》,其中刘备娶孙夫人时,诸葛亮交给赵云三个

锦囊,就是三个策略

  • 锦囊一:到达东吴,先去拜会乔国老
  • 锦囊二:刘备贪念美色不思离开,就对他谎称曹操大军压境
  • 锦囊三:如果被东吴军队追赶,求孙夫人解围

策略模式的UML类图如下:

你有张良计,我有过墙梯之策略模式_css_02

主要角色分析:

  • 抽象策略角色(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<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            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);
            }
        }
    }

举报

相关推荐

0 条评论