概述
概念
策略模式是一种行为型设计模式,它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
组成
1、Context(上下文):用于维护策略类的引用,并在运行时根据需要选择合适的策略。
2、Strategy(策略):定义一个公共接口,用于封装不同的算法或行为。
3、ConcreteStrategy(具体策略):实现策略接口,提供具体的算法或行为。
应用场景
当一个系统需要根据不同的情况选择不同的算法或行为时,可以使用策略模式。
当一个类中有多个条件语句,每个条件语句对应一个算法或行为时,可以考虑使用策略模式简化代码。
注意事项
策略模式将算法或行为封装在不同的策略类中,因此需要对策略类进行合理的设计和组织。
策略模式需要在运行时动态选择策略,因此需要在客户端代码中设置策略的选择逻辑。
类图
衍化过程
需求
商场根据不同的促销活动,以不同的方式对商品进行折扣计算和结算。具体来说,商场收银的需求可以分为以下几个阶段的变化过程:
- 初始需求:商场最开始只有一种收费方式,即正常收费,即不打折不返现,直接按照原价进行结算。
- 变化需求1:商场决定进行促销活动,对部分商品进行打折处理。这时,商场需要根据商品的折扣率来计算折扣后的价格,并进行结算。
- 变化需求2:商场进一步决定进行满减活动,即满足一定条件后,可以返现一定金额。这时,商场需要根据商品的价格和满减条件来计算返现后的价格,并进行结算。
- 变化需求3:商场希望能够根据不同的促销活动,动态地选择不同的收费方式。这时,商场引入了策略模式,将不同的收费方式封装在不同的策略类中,并在运行时根据需要选择合适的策略进行结算。
前两版比较简单,这里不再赘述,主要从需求3说起:
分为简单工厂实现、策略模式实现、简单工厂+策略模式
简单工厂实现
图
代码
收费相关类
//收费抽象类 abstract class CashSuper { public abstract double acceptCash(double money); } //正常收费类 public class CashNormal extends CashSuper { @Override public double acceptCash(double money) { return money; } } //打折收费类 public class CashRebate extends CashSuper { private double moneyRebate=1; public CashRebate(String moneyRebate){ this.moneyRebate= Double.parseDouble(moneyRebate); } @Override public double acceptCash(double money) { return money*moneyRebate; } } //满减收费类 public class CashReturn extends CashSuper { private double moneyCondtion; private double moneyReturn; public CashReturn(String moneyCondition,String moneyReturn){ this.moneyCondtion= Double.parseDouble(moneyCondition); this.moneyReturn= Double.parseDouble(moneyReturn); } @Override public double acceptCash(double money) { double result=money; if (money>=moneyCondtion){ result=money-Math.floor(money/moneyCondtion)*moneyReturn; } return result; } }
工厂
public class CashFactory { public CashSuper creatCashAccept(String type) { CashSuper cs = null; switch (type){ case "正常收费": cs=new CashNormal(); break; case "满300返100": cs=new CashReturn("300","100"); break; case "打八折": cs=new CashRebate("0.8"); break; } return cs; }
客户端
public class Client { public static void main(String[] args) { CashFactory factory=new CashFactory(); CashSuper cs=factory.creatCashAccept("满300返100"); double result=cs.acceptCash(300); System.out.println(result); } }
策略模式
图
类图
NS图
代码
收费上下文类
public class CashContext { private CashSuper cs; public CashContext(CashSuper csuper){ this.cs=csuper; } public double getResult(double money){ return cs.acceptCash(money); } }
客户端
public class Client { public static void main(String[] args) { //传的是不同的策略对象 CashContext selectNormal = new CashContext(new CashNormal()); CashContext selectRebate = new CashContext(new CashRebate("0.8")); CashContext selectReturn = new CashContext(new CashReturn("300","100")); System.out.println("选择正常:"+selectNormal.getResult(300)); System.out.println("选择打八折:"+selectRebate.getResult(300)); System.out.println("选择满减:"+selectReturn.getResult(300)); } }
策略模式+简单工厂
图
代码
收费上下文类(其中包括简单工厂)
public class CashContext { private CashSuper cs=null; //参数是个字符串,而不是收费策略对象 public CashContext(String type){ switch (type){ case "正常收费": cs=new CashNormal(); break; case "满300返100": cs=new CashReturn("300","100"); break; case "打8折": cs=new CashRebate("0.8"); break; } } public double getResult(double money){ return cs.acceptCash(money); } }
客户端
public class Client { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入销售模式:"); String type = scanner.nextLine(); //传的是字符串,而不是具体的策略类 CashContext cash = new CashContext(type); System.out.println("请输入原价"); double price = Double.parseDouble(scanner.nextLine()); System.out.println("最后收费" + cash.getResult(price)); } }
总结升华
版本迭代的优化点及意义
1.前两版到简单工厂
将算法封装,每一个优惠策略都是一个单独的类,而且它们都继承自一个抽象类,抽象类是此版本的一个巨大进步,出现了面向对象以及类的概念,后续的扩充、维护、复用打下了基础。
2.简单工厂到策略模式
使用简单工厂违反开闭原则,考虑到了算法变化性,要这些算法随时可以互相替换,也正是策略模式概念中提到的,而封装变化点是面向对象一种重要的思维方式。
3.策略模式到简单工厂+策略模式
策略模式中实例化对象还是交给了客户端去完成,结合了简单工厂之后,实例化对象由CashContext来完成,可以在客户端消除条件语句。
另外,简单工厂模式客户端需要认识CashSuper和CashFactory,而简单工厂+策略模式,客户端之需要认识CashContext一个类就可以,降低了耦合性。
什么样的思路进行衍化的
有限到无限:
依据业务需求,如果存在潜在的需要,就用无限的思维去进行设计(看到switch case就要思考是否需要无限的思维)
如何去做到无限,使用想象力与创造力把有限的需求变成无限的需求,同时使用有限的方法去实现,落实到代码上是依据软件工程的7大原则和23个设计模式(独立或组合),达到可扩充、可复用、可维护的目标。
扩展思考–如何理解策略与算法
策略模式中提到策略模式定义了算法家族,看类图的时候貌似策略和算法是一个概念,但是两者真的是一样的吗,如无必要勿增实体。那它们是什么关系呢,有没有一种可能,策略和算法并不是一一对应的关系,而独立算法和算法的组合都可以称之为策略呢,就像类图中Strategy与Context是聚合关系。这只是一个想法,策略模式也没有结束,后续还有策略模式+工厂方法+反射的实现,以及我所猜测的算法的组合也可称之为策略,敬请期待。