策略模式

策略模式(Strategy Pattern)

定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化。
策略模式中包含以下几个角色:

  • Context(环境类)
    环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。 对于Context类而言,在它与抽象策略类之间建立一个关联关系,其典型代码如下所示:
1
2
3
4
5
6
7
8
9
10
class Context {
private AbstractStrategy strategy; //维持一个对抽象策略类的引用
public void setStrategy(AbstractStrategy strategy) {
this.strategy= strategy;
}
//调用策略类中的算法
public void algorithm() {
strategy.algorithm();
}
}
  • Strategy(抽象策略类)
    它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
1
2
3
abstract class AbstractStrategy{ //抽象类或者接口都可以
public abstract void algorithm();//声明抽象算法
}
  • ConcreteStrategy(具体策略类)
    它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
1
2
3
4
5
ConcreteStrategyA extends AbstractStrategy{
public void algorithm(){
//算法的具体实现
}
}

为了提高系统的灵活性和可扩展性,可以将具体策略类的类名存储在配置文件中,并通过工具类XMLUtil来读取配置文件并反射生成对象,XMLUtil类的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0"?>
<config>
<className>StudentDiscount</className>
</config>
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
public static Object getBean() {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
//获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}

策略模式用于算法的自由切换和扩展,它是应用较为广泛的设计模式之一。策略模式对应于解决某一问题的一个算法族,允许用户从该算法族中任选一个算法来解决某一问题,同时可以方便地更换算法或者增加新的算法。只要涉及算法的封装、复用和切换都可以考虑使用策略模式。符合面向对象的依赖倒置,开闭原则和里氏替换的设计原则