一、策略模式的定义
定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。
分析:策略模式定义和封装了一系列的算法,他们是可以相互替换的,也就是说它们具有共性,而它们的共性就体现在策略接口的行为上,另外为了达到最后一句话的目的,也就是说让算法独立于使用它的客户而独立变化,我们需要让客户端依赖于策略接口。
二、策略模式的使用
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别时;
2.需要安全地封装多种同一类的操作时;
3.出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。
三、策略模式使用的目的
使用策略模式(同样针对于所有的方案设计)的时候,需要对项目的扩展性,降低复杂度。分析项目中变化与不变的部分,提取变化的部分,抽象成接口+实现。
面向对象编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类,即区分这些类的只是他们的直接行为。
四、策略模式图
这个模式涉及到三个角色:
1.环境(Context)角色:持有一个Strategy的引用
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现,此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
分别封装接口,实现算法族,超类里面 放行为接口对象,在子类里面具体设定行为接口对象,原则就是分离变化部分,封装接口,基于接口编程各种功能。
五、策略模式的典型
抽象策略类
public interface Strategy { /** * 策略方法 */ void StrategyInterface(); }
具体策略类
public class ConcreteStrategyA implements Strategy{ @Override public void StrategyInterface() { // TODO Auto-generated method stub //相关业务 } }
public class ConcreteStrategyB implements Strategy{ @Override public void StrategyInterface() { // TODO Auto-generated method stub //相关业务 } }
public class ConcreteStrategyC implements Strategy{ @Override public void StrategyInterface() { // TODO Auto-generated method stub //相关业务 } }
环境角色类
public class Context { //持有一个具体策略的对象 private Strategy strategy; /** * 构造函数,传入一个具体策略对象 * @param strategy 具体策略对象 */ public Context(Strategy strategy){ this.strategy = strategy; } /** * 策略方法 */ public void contextInterface(){ strategy.StrategyInterface(); } }
六、策略模式实例
某网站推出3种会员,分别为会员,超级会员和黄金会员,还有普通人,针对不同类别的顾客,购买东西时有不同的打折方式,并且一个顾客每消费10000就增加一个级别,普通人原价,会员打九折,超级会员打八折,黄金会员打七折,那么就可以使用策略模式。
策略接口
public interface CalPrice { /** * 最终价格 */ double CalPrice (double orgnicPrice); }
策略接口实现
public class Orgnic implements CalPrice{ @Override public double CalPrice(double orgnicPrice) { // TODO Auto-generated method stub return orgnicPrice; } }
public class Vip implements CalPrice { @Override public double CalPrice(double orgnicPrice) { // TODO Auto-generated method stub return orgnicPrice * 0.9; } }
public class SuperVip implements CalPrice { @Override public double CalPrice(double orgnicPrice) { // TODO Auto-generated method stub return orgnicPrice * 0.8; } }
public class GoldVip implements CalPrice { @Override public double CalPrice(double orgnicPrice) { // TODO Auto-generated method stub return orgnicPrice * 0.7; } }
环境角色
public class Context { private double totalAmount = 0;//消费的zonge private double amount = 0;//单次消费 private CalPrice calPrive = new Orgnic();//策略 public void buy(double amount){ this.amount = amount; totalAmount += amount; if(totalAmount >= 30000){ calPrive = new GoldVip(); }else if(totalAmount >= 20000){ calPrive = new SuperVip(); }else if(totalAmount >= 10000){ calPrive = new Vip(); } } public double calLastAmount(){ return calPrive.CalPrice(amount); } }
七、策略模式的注意点
1.分析项目的变化部分(当前存在的变化部分以及项目后期迭代可能存在的变化部分)与不变化部分
2.多用组合,少用继承,用行为类的组合,而不是行为的继承(继承会使得父类的影响扩展到所有子类),更有弹性
3.如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
策略模式时用来封装算法的,但在实践中,发现可以用它来封装几乎任何类型规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种可能发生的变化。
但是在策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式使用对象,这本身并没有解除客户端需要选择判断的压力,解决这一问题的方法是使用策略模式和简单工厂模式结合,选择具体实现的职责也由策略实用类Context来承担,这就最大化减轻了客户端的职责。