1. 程式人生 > >設計模式-策略模式學習筆記

設計模式-策略模式學習筆記

scan disco result 簡單 exceptio jpg alc discount 分享

前言:策略模式是和簡單工廠一起在幾天前學的,今晚有空正好寫下來

策略模式

策略模式是定義一組算法,將每一種算法都封裝成共同接口的獨立類中,讓它們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶。


  • 優缺點

優點:

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


  • 總結

策略模式使得每種算法都能夠靈活的替換,並且在新增算法時不修改原有代碼,不管是耦合性還是可擴展性都被大大的優化了,不過在客戶端調用策略時會出現臃腫的選擇,需要通過其他方式去優化。

設計模式-策略模式學習筆記