策略模式指的是定义一些列的算法,把他们一个个封装起来,目的就是将算法的使用与算法的实现分离开来,避免多重判断条件,更具有扩展性。
策略模式(前端)
下面也是举个例子,现在超市有活动,vip为5折,老客户3折,普通顾客没折,计算***需要支付的金额,如果不使用策略模式,我们的代码可能和下面一样:
1 | function Price(personType, price) { |
在上面的代码中,我们需要很多个判断,如果有很多优惠,我们又需要添加很多判断,这里已经违背了刚才说的设计模式的六大原则中的开闭原则了,如果使用策略模式,我们的代码可以这样写:
1 | // 对于vip客户 |
总结:在上面的代码中,通过策略模式,使得客户的折扣与算法解藕,又使得修改跟扩展能独立的进行,不影到客户端或其他算法的使用。
当我们的代码中有很多个判断分支,每一个条件分支都会引起该“类”的特定行为以不同的方式作出改变,这个时候就可以使用策略模式,可以改进我们代码的质量,也更好的可以进行单元测试。
策略模式(后端)
其中,Context是上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用;Strategy是策略类,用于定义所有支持算法的公共接口;ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。
1. Context上下文
Context上下文角色,也叫Context封装角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
1 | 1 public class Context { |
2. 策略角色
抽象策略角色,是对策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。algorithm是“运算法则”的意思。
1 | 1 public abstract class Strategy { |
3. 具体策略角色
用于实现抽象策略中的操作,即实现具体的算法,下方用print代替。测试类共3个ConcreteStrategy,其它两个类与ConcreteStrategyA同理,就不再赘述了。
1 | 1 public class ConcreteStrategyA extends Strategy { |
4. Client客户端
下面依次更换策略,测试一下策略模式。
1 | 1 public class Client { |
策略模式的应用
1. 何时使用
一个系统有许多类,而区分它们的只是他们直接的行为时
2. 方法
将这些算法封装成一个一个的类,任意的替换
3. 优点
算法可以自由切换
避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
扩展性良好,增加一个策略只需实现接口即可
4. 缺点
策略类数量会增多,每个策略都是一个类,复用的可能性很小
所有的策略类都需要对外暴露
5. 使用场景
多个类只有算法或行为上稍有不同的场景
算法需要自由切换的场景
需要屏蔽算法规则的场景
6. 应用实例
出行方式,自行车、汽车等,每一种出行方式都是一个策略
商场促销方式,打折、满减等
Java AWT中的LayoutManager,即布局管理器
7. 注意事项
如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题