1. 程式人生 > >設計模式學習筆記(三)——策略模式

設計模式學習筆記(三)——策略模式

count forname tst code tchar 類名 適用於 動態 自由

一、概述

  策略模式屬於對象的行為模式。其用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們之間可以互相替換。策略模式使得算法可以在不影響客戶端的情況下發生變化。

  策略模式是對算法的封裝,把一系列的算法分別封裝到對應的類中,並且這些類實現相同的接口,相互之間可以互相替換。在策略模式中,調用算法的主體是封裝到了封裝類Context中,抽象策略Strategy一般是一個接口,目的只是為了定義規範,裏面一般不包含邏輯。其實,這只是通用實現,而在實際編程中,因為各個具體策略實現類之間難免存在一些相同的邏輯,為了避免重復的代碼,我們常常使用抽象類來擔任Strategy的角色,在裏面封裝公共的代碼。

二、實現策略模式

  需求:

  收費系統   分別有三種收費方式:   ①正常收費   ②打折收費   ③返利收費   客戶端發送(參數)到業務層,判斷參數屬於哪種收費模式,然後進行收費.   要求:用到單一設計原則,開閉原則.   ====================================================================   分析:   收費有各種收費方式,那麽可以將收費抽象出來,定義一個接口,以後出現哪種收費的時候,就實現收費接口.   技術分享圖片    Charge(收費接口):定義一個抽象收費接口,讓子類去實現它。   NormalCharge(正常收費):
實現收費接口,定義具體的收費算法;具體策略類。
  DiscountCharge(打折收費):實現收費接口, 定義具體的收費算法;具體策略類。   RebateCharge(返利收費):實現收費接口, 定義具體的收費算法;具體策略類。   ChargeFormDto(收費傳輸對象):負責傳輸收費所需的參數,封裝客戶端傳輸的參數,有收費類型、總價、折扣、滿額度、返額度。   ChargeContext(處理收費的業務對象):負責收費調用的業務,調用具體收費策略、計算。   ChargeClient(收費客戶端):收費客戶端。   Charge(收費接口):
/**
 * 收費接口
 * @author
Administrator * */ public interface Charge { /** * 收費 * @param chargeFormDto * @return */ double charge(ChargeFormDto chargeFormDto); }

  

  NormalCharge(正常收費):

/**
 * 具體 正常收費策略
 * @author Administrator
 *
 */
public class NormalCharge implements Charge {

    @Override
    public double charge(ChargeFormDto chargeFormDto) {
        System.out.println("正常收費: " + chargeFormDto.getPrice());
        return chargeFormDto.getPrice();
    }

}

  DiscountCharge(打折收費):

/**
 * 具體 打折收費策略類
 * @author Administrator
 *
 */
public class DiscountCharge implements Charge {

    @Override
    public double charge(ChargeFormDto chargeFormDto) {
        double price = chargeFormDto.getPrice() - chargeFormDto.getPrice() * chargeFormDto.getRebate();
        System.out.println("打折收費: " + price);
        return price;
    }
    
}

  RebateCharge(返利收費):

/**
 * 具體 返利消費策略類
 * @author Administrator
 *
 */
public class RebateCharge implements Charge {

    @Override
    public double charge(ChargeFormDto chargeFormDto) {
        double price = chargeFormDto.getPrice() - 
                chargeFormDto.getPrice() / chargeFormDto.getFullCash() * chargeFormDto.getReturnCash();
        System.out.println("返利消費, 消費:" + chargeFormDto.getPrice() + ", 返利: " + price);
        return price;
    }

}

  ChargeFormDto(收費傳輸對象):

/**
 * 收費表單傳輸對象
 * @author Administrator
 *
 */
public class ChargeFormDto implements Serializable {

    /**
     * 打折類型
     */
    private String type;
    
    /**
     * 總價
     */
    private double price;
    
    /**
     * 折扣
     */
    private double rebate;
    
    /**
     * 滿額度
     */
    private double fullCash;
    
    /**
     * 反額度
     */
    private double returnCash;

    public ChargeFormDto() {
        super();
    }

    public ChargeFormDto(String type, double price, double rebate, double fullCash, double returnCash) {
        super();
        this.type = type;
        this.price = price;
        this.rebate = rebate;
        this.fullCash = fullCash;
        this.returnCash = returnCash;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public double getRebate() {
        return rebate;
    }

    public void setRebate(double rebate) {
        this.rebate = rebate;
    }

    public double getFullCash() {
        return fullCash;
    }

    public void setFullCash(double fullCash) {
        this.fullCash = fullCash;
    }

    public double getReturnCash() {
        return returnCash;
    }

    public void setReturnCash(double returnCash) {
        this.returnCash = returnCash;
    }
    
}

  ChargeContext(處理收費的業務對象):

/**
 * 處理收費的Context (業務類)
 * @author Administrator
 *
 */
public class ChargeContext {

    /**
     * 收費接口
     */
    private Charge charge;
    
    /**
     * 收費傳輸對象
     */
    private ChargeFormDto dto;
    
    public ChargeContext(ChargeFormDto dto) {
        this.dto = dto;
        
        try {
            charge = (Charge) Class.forName(dto.getType()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 返回收費結果
     * @return
     */
    public double account() {
        return charge.charge(dto);
    }
}

  ChargeClient(收費客戶端):

public class ChargeClient {

    public static void main(String[] args) {
        // 創建收費清單
        ChargeFormDto dto = new ChargeFormDto();
        dto.setType("edu.strategy.strategy.impl.NormalCharge"); // 輸入具體策略類的路徑
        dto.setPrice(300);
        
        // 創建收費服務
        ChargeContext context = new ChargeContext(dto);
        
        // 計算
        context.account();
    }
    
}

  運行結果:

  技術分享圖片

  收費類型那裏現在是寫具體類名,但是這樣不太方便,這裏可以優化,可以選擇讀取配置文件與萬能工廠的方式進行改進。

三、總結

   優點:

  1、易於擴展;策略模式提供了對 "開閉原則" 的完美支持,用戶可以在不修改原有系統的基礎上選擇算法或行為,也可以靈活地新增新的算法或行為。

  2、策略類之間可以自由切換;由於策略類都實現同一個接口,所有使它們間可以自由切換

  3、解耦;將算法的責任和本身進行解耦,使得算法可獨立使用外部而變化,客戶端方法根據外部條件選擇不同策略來解決不同的問題。

  缺點:

  1、客戶端必須指定所有的策略類,並自行決定使用哪一個策略類。

  2、策略模式將造成上次很多策略類。

  適用性:

  適用於動態選擇多種負責行為:1、負責的算法/數據結構;2、類的行為/方法,提高行為的保密性。

設計模式學習筆記(三)——策略模式