策略模式(Strategy Pattern)——算法的封装与切换
说明:设计模式系列文章是读刘伟
所著《设计模式的艺术之道(软件开发人员内功修炼之道)》
一书的阅读笔记。个人感觉这本书讲的不错,有兴趣推荐读一读。详细内容也可以看看此书作者的博客https://blog.csdn.net/LoveLion/article/details/17517213
。
模式概述
俗话说:条条大路通罗马。在很多情况下,实现某个目标的途径不止一条,例如我们在外出旅游时可以选择多种不同的出行方式,如骑自行车、坐汽车、坐火车或者坐飞机。
这就是变化的地方,可根据实际情况(距离、预算、时间、舒适度等)来选择一种出行方式。
在软件开发中,也常会遇到类似的情况,实现某一个功能有多种算法,此时就可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。
下面介绍一种为了适应算法灵活性而产生的设计模式——策略模式。
模式定义
策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开。
将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合依赖倒转原则
。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。
策略模式定义如下:
策略模式(
Strategy Pattern
):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy
)。策略模式是一种对象行为型模式。
模式结构图
策略模式结构并不复杂,但我们需要理解其中环境类Context
的作用,其结构如下图所示:
在策略模式结构图中包含如下几个角色:
Context
(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。Strategy
(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。ConcreteStrategy
(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
模式伪代码
抽象策略类(Strategy
)典型代码如下:
/**
* 定义抽象算法
*/
public interface Strategy {
void algorithm();
}
具体策略类(ConcreteStrategy
)封装每一种具体的算法,典型代码如下:
/**
* 一种具体的算法
*/
public class ConcreteStrategy implements Strategy {
@Override
public void algorithm() {
// 具体的算法实现
}
}
Context
引用抽象策略,典型代码如下:
public class Context {
// 抽象策略
private Strategy strategy;
/**
* 业务逻辑
*/
public void service() {
// ...
// 调用具体的算法实现
strategy.algorithm();
// ...
}
}
这样就将算法的定义和使用分离开来,可独立扩展新的算法。
模式应用
待完善。
模式总结
策略模式提供了一种可插拔式(Pluggable
)算法的实现方案。
策略模式实用性强、扩展性好,在软件开发中得以广泛使用,是使用频率较高的设计模式之一。
主要优点
- 符合开闭原则,可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为
- 将算法的定义和使用分离开来,符合单一职责原则,可最大程度地复用算法
主要缺点
系统可能会产生很多具体策略类。
适用场景
策略模式用于算法的自由切换和扩展。
策略模式对应于解决某一问题的一个算法族,允许用户从该算法族中任选一个算法来解决某一问题,同时可以方便地更换算法或者增加新的算法。
只要涉及到算法的封装、复用和切换都可以考虑使用策略模式。