前言:策略模式是和简单工厂一起在几天前学的,今晚有空正好写下来
策略模式
策略模式是定义一组算法,将每一种算法都封装成共同接口的独立类中,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
- 优缺点
优点:
- 满足开放-封闭原则(扩展算法时,直接新增算法类,不用修改上下文)
- 降低了策略和策略调用者的耦合度
- 一个算法发生修改时,其他算法可以不用暴露
- 简化了算法的单元测试
缺点:
- 每个算法独立成类,算法越多,类越来越多
- 所有的策略类都用暴露出去,客户端必须要知道所有的策略类
- 结构
Strategy:抽象的策略(一个借口或抽象类)
ConcreteStrategy:具体的策略(实现了Strategy的算法类)
Context:策略上下文(策略模式的上下文类,持有Strategy类的引用,也可将策略的参数放置在上下文类中)
- 代码
引用《大话设计模式》中的例子,商场购物有优惠,现有优惠方案:1、打折 2、满减,可能会有优惠方案:1、赠送积分
抽出父类策略类。
/** * @ Author :fonxi * @ Date :2019/5/10 2:56 * @ Description:策略类 */ public interface Super { Double count(Context ctx); }
然后将每一种优惠方案当做一种算法,独立封装成具体策略类。
/** * @ Author :fonxi * @ Date :2019/5/10 2:56 * @ Description:具体策略-折扣类 */ public class Discount implements Super{ @Override public Double count(Context ctx) { return ctx.getDiscountRate()*ctx.getMoney(); } }
/** * @ Author :fonxi * @ Date :2019/5/10 2:56 * @ Description:具体策略-返利类 */ public class Rebate implements Super{ @Override public Double count(Context ctx) { if(ctx.getMoney()>ctx.getRebateMoeny()){ return ctx.getMoney() - Math.floor(ctx.getMoney()/ctx.getRebateMoeny()) * ctx.getRebateValue(); } return ctx.getMoney(); } }
上下文中放置具体算法所需的参数,持有策略类的引用,并返回具体调用的策略算法。
/** * @ Author :fonxi * @ Date :2019/5/10 3:01 * @ Description:上下文 */ @Data public class Context {
//总金额 private Double money; //折扣 private Double discountRate; //到达额度 产生返利 private Double rebateMoeny; //返利值 private Double rebateValue; //持有一个策略对象 private Super superObject; public Context(Double rebateMoeny,Double rebateValue,Double money,Double discountRate,Super superObject){ this.rebateMoeny = rebateMoeny; this.rebateValue = rebateValue; this.money = money; this.discountRate = discountRate; this.superObject = superObject; } public Double getResult(Context ctx){ return superObject.count(ctx); } }
在客户端,根据需求选择不同的策略,然后通过策略上下文得到不同的策略实现。
/** * @ Author :fonxi * @ Date :2019/5/10 3:10 * @ Description:客户端选择类 */ public class Calculator { public void print(){ Scanner s = new Scanner(System.in); Context context = null; //折扣 Double discountRate = null; //到达额度 产生返利 Double rebateMoeny = null; //返利值 Double rebateValue = null; try { System.out.println("请输入总金额"); Double money = s.nextDouble(); System.out.println("请选择折扣方式:1、打折2、返利"); String type = s.next(); if(type.equals("1")){ System.out.println("请输入折扣"); discountRate = s.nextDouble(); } else if(type.equals("2")){ System.out.println("请输入满减额度"); rebateMoeny = s.nextDouble(); System.out.println("请输入满减值"); rebateValue = s.nextDouble(); } Super superObject = null; switch (type){ case "1": superObject = new Discount(); break; case "2": superObject = new Rebate(); break; default: System.out.println("输入选择有误"); break; } context = new Context(rebateMoeny,rebateValue,money,discountRate,superObject); System.out.println("结算金额是:"+context.getResult(context)); }catch (Exception e){ System.out.println("请输入有误"+e.getMessage()); } } }
- 总结
策略模式使得每种算法都能够灵活的替换,并且在新增算法时不修改原有代码,不管是耦合性还是可扩展性都被大大的优化了,不过在客户端调用策略时会出现臃肿的选择,需要通过其他方式去优化。