设计模式——策略模式

203 阅读2分钟

概述

由于环境/条件的不同,完成某一项任务往往有不同的算法,每一个算法称为一个策略,我们定义一些独立的类来封装不同的算法,这些类称为策略Strategy。

该模式下的角色有:

(1)抽象策略角色:通常是一个接口或抽象类

(2)具体策略角色:实现策略接口或继承抽象类。它包装了相关的算法。

(3)环境/条件角色Context:它持有一个策略接口/抽象类的引用strategy。根据传入参数strategy的不同,它会调用不同的策略。

示例

假设两个数的计算方式分为加法和减法,现给出一个式子:

num1 @ num2,其中 @ 符号表示加法或减法。我们用代码来实现这个策略

首先定义抽象策略角色——计算方式接口Strategy:

public interface Strategy {
    int doOperation(int num1, int num2);
}

然后是具体策略角色——两个计算方式接口的实现类:加法类和减法类

public class AddOperation implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}
public class SubstractOperation implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}

然后是环境/条件类Context,可以将它理解为符号@,它持有一个策略类,

public class Context {
    private Strategy strategy;

    public Context() { }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public int computing(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}

测试一下:

public class Test {
    public static void main(String[] args) {
        Context context = new Context();
        context.setStrategy(new AddOperation());
        System.out.println("3 + 33 = " + context.computing(3, 33));
        context.setStrategy(new SubstractOperation());
        System.out.println("3 - 33 = " + context.computing(3, 33));
    }
}

总结

优点

(1)可以根据条件Context对象的不同来选择不同策略。

(2)避免使用多重条件判断

(3)扩展性良好,若要新加一个策略,直接新写一个具体策略类即可。

缺点

(1)策略类可能会增多,且所有的策略类需要对外暴露。

线程池中的策略模式

在线程池的构造函数中,有一个RejectedExecutionHandler类型参数对象handler,它表示拒绝策略,有四种实现方式:

  • 直接抛出异常
  • 使用调用者的线程来处理
  • 直接丢掉这个任务
  • 丢掉最老的任务
   private volatile RejectedExecutionHandler handler;

	public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        //省略部分代码
        this.handler = handler;
    }
    
    final void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }

参考资料

菜鸟教材