意图
定义了算法簇,分别封装起来,让他们之间可以互相替换。策略模式让算法得变化独立于使用算法得客户。
动机
生活中,我们常常遇到实现某种目标存在多种方式可供选择的情况,例如:我们可以选择自驾、搭地铁、搭公交或者骑自行车等方式上下班。
类似的,在开发某一个功能时也可能存在多种算法或者策略,可以根据环境或者条件的不同选择不同的算法或者策略来实现该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。
适用性
策略模式常见的使用场景如:
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
- 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
- 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的数据结构。
- 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
结构
策略模式模式的主要角色有:
- 抽象策略类(
Strategy
):定义了一个算法族; - 具体策略类(
ConcreteStrategy
):提供具体的算法实现; - 环境类(
Context
):持有一个策略类的引用,最终给客户端调用。
实现
// 抽象策略接口
public interface Strategy {
// 策略方法
void strategyMethod();
}
//具体策略类A
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyMethod() {
System.out.println("执行 ConcreteStrategyA 的策略方法。。。");
}
}
//具体策略类B
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyMethod() {
System.out.println("执行 ConcreteStrategyB 的策略方法。。。");
}
}
// 环境类
public class Context {
private Strategy strategy;
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
// 通过 set 不同的 strategy 对象,而动态地改变调用的策略方法
public void operation() {
strategy.strategyMethod();
}
}
// 测试客户端
public class TestClient {
public static void main(String[] args) {
Context context = new Context();
Strategy concreteA = new ConcreteStrategyA();
Strategy concreteB = new ConcreteStrategyB();
context.setStrategy(concreteA);
context.operation();
context.setStrategy(concreteB);
context.operation();
}
}
已知应用
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
相关模式
策略模式与模板方法模式区别:
1、类之间的关系不同:策略模式使用对象组合的方式,客户可以在运行时改变他们的算法,设计更有弹性;而模板方法模式区使用的继承的方式,可以把重复用到的代码都封装到基类中,让所有子类共享,代码更紧凑,效率更高。
2、执行流程:模板模式是按照一定步骤执行程序的,任何一个节点的重载不会影响到这个次序;而策略模式各各算法彼此完全独立,没有次序要求。
参考资料
- 《
Head First
设计模式》 - 图说设计模式
- Java设计模式:23种设计模式全面解析(超级详细)