设计模式之策略模式【5】
一、模式定义
它定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法变化,不会影响到使用算法的客户。
二、模式分析
1.策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它们可以以相同的方式调用所有算法,减少了各种算法类与是哟算法类之间的耦合。
2.策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或者行为。继承有助于析取出这些算法中的公共功能。
3.策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
三、主要角色
抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口,所有具体的策略类都要实现这个接口。环境(上下文)类Context 使用这个接口调用具体的策略类。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
环境(Context)类:用于配置一个具体的算法策略对象 ,维持一个策略接口类型的引用( Reference ),并且可以定义一个让接口 Strategy 的具体对象访问的接口。在简单情况下,Context 类可以省略。
策略模式包含的个核心角色:
- 环境(Context):维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
- 抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
- 具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。
策略模式通过将算法与使用算法的代码解耦,提供了一种动态选择不同算法的方法。客户端代码不需要知道具体的算法细节,而是通过调用环境类来使用所选择的策略。
四、模式特点
4.1 优点
-
多个具体策略之间可以自由切换
由于策略类都实现同一个接口,所以使它们之间可以自由切换。
-
易于扩展
增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“
-
避免使用多重条件选择语句(if else),充分体现面向对象设计思想
当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句。
4.2 缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。也就是说客户程序必须知道不同策略接口的各个子类的行为,必须理解每个子类有哪些不同。
- 所有策略类都需要暴露:策略类需要对外公开,以便可以被选择和使用。
- 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
- 策略类数量增多:每增加一个算法,就需要增加一个策略类。
- 无法同时在客户端使用多个策略类。也就是说,在使用策略模式时,客户端每次只能使用一个策略类,不支持使用一个策略类完成部分功能后再使用另一个策略类来完成剩余功能的情况。
五、使用场景
- 一个系统需要动态地在多种算法/策略中选择一种时,当有多个仅在行为上不同但是任务相关的类存在时,可将每个算法封装到策略类中。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
- 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。
- 当一个算法使用的用户不应该知道的数据时,使用策略模式可以将算法实现细节隐藏起来 ,避免暴露与算法相关的复杂细节。注意 虽然可以将算法实现细节封装起来,但是客户程序必须知道各个策略子类的接口。
六、案例实践
案例:优雅的Java应用程序的启停钩子框架
七、案例分析
7.1 旅游出行方式
先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。
7.2 软件工程师的开发工具的选择
作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进行开发,也可以使用eclipse进行开发,也可以使用其他的一些开发工具。
在软件开发中,我们也常常会遇到类似的情况,实现某一个功能有多条途径,每一条途径对应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。
7.3 代码演示
我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类。
StrategyPatternDemo,我们的演示类使用 Context 和策略对象来演示 Context 在它所配置或使用的策略改变时的行为变化。
1) 创建1个接口 : Strategy
public interface Strategy { public int doOperation(int num1, int num2); }
2) 创建实现接口的实体类
OperationAdd
public class OperationAdd implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 + num2; } }
OperationSubtract
public class OperationSubtract implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 - num2; } }
OperationMultiply
public class OperationMultiply implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 * num2; } }
3) 创建 Context 类
public class Context { private Strategy strategy; public Context(Strategy strategy){ this.strategy = strategy; } public int executeStrategy(int num1, int num2){ return strategy.doOperation(num1, num2); } }
4) 使用 Context 来查看当它改变策略 Strategy 时的行为变化 : StrategyPatternDemo
public class StrategyPatternDemo { public static void main(String[] args) { Context context = new Context(new OperationAdd()); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); context = new Context(new OperationSubtract()); System.out.println("10 - 5 = " + context.executeStrategy(10, 5)); context = new Context(new OperationMultiply()); System.out.println("10 * 5 = " + context.executeStrategy(10, 5)); } }
out:
10 + 5 = 15 10 - 5 = 5 10 * 5 = 50
X、引用文献
[1] 《大话设计模式》.策略模式.程杰.清华大学出版社
[3] 策略模式 - 菜鸟教程

本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!