一,例子引入
在商场中我们会遇到这样的问题,就是对于会员和普通顾客的优惠不同,节假日和平常的日子不同,如果我们只写一个算法的话,在维护的时候就会出现很多的麻烦
那么有什么解决办法呢?
我们这个时候就可以采用策略模式:
各个职责的角色:
环境角色(CashContext):里面有一个Strategy类的引用(上下文对象),负责和具体的策略类交互
抽象角色(CashSuper):这是一个抽象角色,通常由一个接口或者抽象类实现。此角色给出所有的具体策略类所需的接口
具体策略角色(ConcreteStrategy):包装了相关的算法或行为
策略模式的用意:
-
针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得他们可以相互替换,策略模式使得算法可以在不影响客户端的情况下发生变化
-
使用策略模式可以把行为和环境分割开来。环境类负责维持和查询行为类,各种算法则在具体策略类中提供
-
由于算法和环境分割开来,算法的增减和修改都不会影响环境和客户端。只需要实现新的策略类,并在客户端登记即可,策略模式相当于可插入算法
以商场收费为例的具体代码:
在上下文环境类中,我们可以发现,在它将策略类放在了构造函数中,那么客户端可以根据选择创建出相应场景的上下文对象类
二,解析策略模式
-
策略模式的功能:把具体算法从具体业务处理中独立
-
如果出现多个if-else语句,那么我们就考虑策略模式
-
算法的平等性:策略算法是形同行为的不同实现
-
谁来实现具体的策略算法:客户端,有上下文选择具体的策略算法
什么时候使用策略模式:
-
出现同一类型的算法,有很多种不同的实现情况,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次
-
出现抽象一个定义了很多行为的类,并且是通过多个if-else语句来选择这些行为的情况,可以使用策略模式来代替这些条件语句
优点:
-
策略模式可以避免让客户设计涉及到不必要接触到的复杂的和与算法有关的数据
-
避免使用使用难以维护的多重条件选择语句
-
更好的扩展
缺点:
-
我们可以发现选择语句还是在客户端中,当我们进行增减算法的时候还是需要修改客户端中的代码
-
客户端必须知道所有的策略类,并自行决定使用哪一个策略类,这就意味着客户端必须要知道这些算法的区别,以便使用选择恰当的算法
-
增加了对象的数目
-
只适用于扁平的算法
本质:
分离算法,选择实现
三,策略模式与简单工厂模式的结合
把分支判断放到环境角色中
也就是说我们本来是在客户端中进行判断的,现在我们把它移动到上下文类中
这样客户端只需要认识上下文类这一个类就可以了
这样的话,降低了耦合性
四,模式的深入
在策略模式中,通常是上下文使用具体的策略实现对象,反过来,策略实现对象也可以从上下文获取所需要的数据,因此可以将上下文当参数传递给策略实现对象
在这种情况下,上下文封装着具体策略对象进行算法运算所需要的数据,具体策略对象通过回调上下文的方法来获取这些数据
例如:在发放工资的时候,如果是直接发放现金,那么这样就不需要员工的卡号,直接进行发放即可
但是如果是通过工资卡发放的话,我们就需要员工的卡号
那么这个时候,我们就需要对于上下文进行扩展
这个UML画的有问题,进行了一个简单的修改,也就是RMBCash对于上下文有引用,在上下文的构造函数中也有对于具体的算法的实例化
进行扩展上下文的方式:
优点:
-
所有策略实现风格更统一,策略需要的数据都统一从上下文来获取,这样在使用方法上也统一
-
在上下文中添加新的数据,别的相应算法也可以用的上,可以视为公共的数据
缺点:
如果只有一个特定的算法来使用这些数据,那么这些数据有一些浪费,另外每次添加新的算法都去扩展的话,容易形成复杂的上下文对象层次