1 介绍
1.1 什么是策略模式
策略模式简单的说就是,准备一组算法,并将每一个算法封装起来,使得它们可以互换。
策略模式是一种对象行为型模式。
1.2 解决什么样的问题
策略模式为了解决什么样的问题呢?我们来看一个例子。
超市隔三差五就要办促销活动,每次促销活动的方式不一样,希望找到一种方式,使得营业员只要输入原价再选择活动类型后,就能计算出折扣以后的价钱。
面对这个问题,通常我们想到的解决方案是用if...else或者switch语句写出逻辑分支。这样做会有两个问题:
- 如果要增加新的折扣方式,就打破的"开-闭"原则。
2.业务逻辑不能复用。
时间久了这段代码会渐渐成为面条代码,环境和行为会紧密耦合在一起,逐渐腐败,难以维护。
2 原理
2.1 UML图
-
类图
image.png
类图清晰的表明了策略模式结构的参与者。
- Strategy:定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
- ConcreteStrategy:具体策略。以Strategy接口实现某具体算法。
- Context:上下文,用一个ConcreteStrategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口来让Strategy访问它的数据。
-
时序图
image.png
2.2 代码示例
Context示例代码
public class Context{
private Strategy strategy;
Context(Strategy strategy){
this.strategy = strategy;
}
public void contextInterface(){
strategy.strategyInterface();
}
}
Strategy示例代码
public interface Strategy { //这里用接口描述, 也可以使用抽象类
void strategyInterface();
}
ConcreteStrategy示例代码
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
System.out.println("this is ConcreteStrategyA ");
}
}
调用示例
public static void main(String[] args) {
Strategy strategyA = new ConcreteStrategyA();
Context context = new Context(strategyA);
context.contextInterface();
}
运行结果
this is ConcreteStrategyA
2.3 优缺点
-
优点
- 非常易于扩展
策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法(策略),并且可以灵活地增加新的算法(策略)。 - 避免使用多重条件转移语句。
- 算法可以自由切换。
- 非常易于扩展
-
缺点
- 客户端必须知道所有得策略类,并自行决定使用哪一个策略类。这使得策略类定义必须暴露给客户端。
- 造成很多策略类,带来额外的维护开销,如果策略类超过4个,就需要考虑使用混合模式,解决策略类膨胀的问题。
4 适用场景
在以下情况下可以使用策略模式
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
- 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
5 总结
5.1 设计原则
- "开-闭"原则。策略模式是"开-闭"原则的一个极好的应用范例。
- 里氏代换原则。里氏代换原则是策略模式的基础。策略模式要求所有的策略对象都是可以互换的,因此它们都必须是一个抽象策略角色的子类。在客户端则仅知道抽象策略角色类型,虽然变量的真实类型可以是任何一个具体策略角色的实例。
5.2 认识策略模式
- 策略模式的重心
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
- 算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。
所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
- 运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
- 公有的行为
经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。
这其实也是典型的将代码向继承等级结构的上方集中的标准做法。
image.png
参考书籍和文章
- 《Java与模式》,电子工业出版社,阎宏
- 《设计模式——可复用面向对象软件的基础》,机械工业出版社,Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides
- 《图说设计模式》,https://design-patterns.readthedocs.io/zh_CN/latest/index.html
- 《 < JAVA与模式 > 之策略模式》,https://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html
网友评论