一 .概述
如果把方法的实现作为一个参数,那么这个参数就是一个策略,很像我们常常使用的函数式编程.
二 .场景
一个简单的计算价钱的场景:
[1]普通用户所有的价钱为原价
[2]普通会员的九折
[3]黄金会员为八折.
我们一个简单的程序如下:
public class SimpleCounter { public double count(String type,double price) { // 普通会员 if("commons".equals(type)) { return price ; } // 一般的会员 else if("commonvip".equals(type)) { return price * 0.9; } // 黄金会员 else { return price * 0.8; } } }
在这里,我们可能常常出现的一个问题就是具体计算的方法会发生改变.也就是说我们的if这一部分的内容常常需要发生变化,
另外的一个问题,就是计算的种类也会发生变化,也就是说这一部分的方法是非常不稳定的.
我们由此引入一个策略的模式:
/** * 具体的策略,子类实现不同的计算接口 */ public interface Strategy { double count(double price); }
public class CommonStrategy implements Strategy { public double count(double price) { return price; } }
/** * 普通vip的实现 */ public class CommonVipStrategy implements Strategy { public double count(double price) { return price * 0.9; } }
/** * 超级vip的实现 */ public class SuperVipStrategy implements Strategy{ public double count(double price) { return price * 0.8; } }
/** * 策略上下文 */ public interface StrategyContext { Strategy getStrategy(); }
/** * 策略的上下文,主要用来封装一系列策略运行需要的参数 */ public class SimpleStrategyContext implements StrategyContext { private Strategy strategy; public SimpleStrategyContext(Strategy strategy) { this.strategy = strategy; } public double count(double price) { return this.strategy.count(price); } public Strategy getStrategy() { return this.strategy; } }
public class Client { public static void main(String[] args) { //Strategy strategy = new CommonStrategy(); Strategy strategy = new SuperVipStrategy(); SimpleStrategyContext context = new SimpleStrategyContext(strategy); double count = context.count(100d); System.out.println(count); } }
现在我们可以通过这里创建不同的策略进行切换,保证的开闭原则.
现在出现了一个问题,我们每次都需要创建策略接口的子类,客户端在一定程度上就需要知道子类的实现情况.
在这个地方,我们可以使用工厂模式来解决这个问题.
毕竟工厂模式最主要的功能就是选择一个接口的实例的功能.
三 . 策略模式的说明
通过一个策略上下文封装一个策略的具体实现.
然后客户端仅仅只需要和策略的上下文进行交互就可以完成了.
当然,在策略上下文之中,我们可以封装大量的参数信息,帮助策略对象工作的时候的需要.