设计模式-策略模式学习笔记

前言:策略模式是和简单工厂一起在几天前学的,今晚有空正好写下来

策略模式

策略模式是定义一组算法,将每一种算法都封装成共同接口的独立类中,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。


  • 优缺点

优点:

  1. 满足开放-封闭原则(扩展算法时,直接新增算法类,不用修改上下文)
  2. 降低了策略和策略调用者的耦合度
  3. 一个算法发生修改时,其他算法可以不用暴露
  4. 简化了算法的单元测试

缺点:

  1. 每个算法独立成类,算法越多,类越来越多
  2. 所有的策略类都用暴露出去,客户端必须要知道所有的策略类

  • 结构

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());
        }
    }
}

  • 总结

策略模式使得每种算法都能够灵活的替换,并且在新增算法时不修改原有代码,不管是耦合性还是可扩展性都被大大的优化了,不过在客户端调用策略时会出现臃肿的选择,需要通过其他方式去优化。

原文地址:https://www.cnblogs.com/fonxi/p/10851004.html