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

来源:http://www.cnblogs.com/LeslieXia/archive/2016/05/15/5494856.html
-Advertisement-
Play Games

策略模式 定義了演算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。 說明: 1、可以動態地改變對象的行為; 2、各個策略演算法的平等性,各個策略演算法在實現上是相互獨立的,相互之間沒有任何依賴的(由此,策略模式也可以描述為“策略演算法是相同行為的不同實現”); 3、在運 ...


策略模式     定義了演算法族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化獨立於使用演算法的客戶。     說明      1、可以動態地改變對象的行為;     2、各個策略演算法的平等性,各個策略演算法在實現上是相互獨立的,相互之間沒有任何依賴的(由此,策略模式也可以描述為“策略演算法是相同行為的不同實現”);     3、在運行期間,策略模式在某一時刻,只能使用一個具體的策略演算法實現對象,雖然可以動態改變對象行為,但同時只能使用一個;     4、策略模式可以很簡單的擴展新的實現演算法。方法:先寫一個策略演算法來實現新的需求,然後在客戶端使用時指定該實現演算法即可;     5、多個if-elseif語句表達的就是一個平等的功能結構,你要麼執行if,要不你就執行else,或者是elseif,這個時候,if塊裡面的實現和else塊裡面的實現從運行地位上來講就是平等的。而策略模式就是把各個平等的具體實現封裝到單獨的策略實現類了,然後通過上下文來與具體的策略類進行交互。因此多個if-else語句可以考慮使用策略模式。       場景:     1、報價管理系統中,對於銷售部門的人來說,要對不同的客戶報不同的價格。如:對於普通用戶或者新用戶來說,報全價;對老客戶報的價格,統一折扣5%;大客戶報的價格,統一折扣10%。     實現:     A:定義策略介面     

/**

 * 策略,定義計算報價演算法的介面

 */

public interface Strategy {

    /**

     * 計算應報的價格

     * @param goodsPrice 商品銷售原價

     * @return 計算出來的,應該給客戶報的價格

     */

    public double calcPrice(double goodsPrice);

}

   B:具體實現各個報價標準     

/**

 * 具體演算法實現,為新客戶或者是普通客戶計算應報的價格

 */

public class NormalCustomerStrategy implements Strategy{

    public double calcPrice(double goodsPrice) {

       System.out.println("對於新客戶或者是普通客戶,沒有折扣");

       return goodsPrice;

    }

}

/**

 * 具體演算法實現,為老客戶計算應報的價格

 */

public class OldCustomerStrategy implements Strategy{

    public double calcPrice(double goodsPrice) {

       System.out.println("對於老客戶,統一折扣5%");

       return goodsPrice*(1-0.05);

    }

}

/**

 * 具體演算法實現,為大客戶計算應報的價格

 */

public class LargeCustomerStrategy implements Strategy{

    public double calcPrice(double goodsPrice) {

       System.out.println("對於大客戶,統一折扣10%");

       return goodsPrice*(1-0.1);

    }

}

    C:價格類,上下文的實現

/**

 * 價格管理,主要完成計算向客戶所報價格的功能

 */

public class Price {

    /**

     * 持有一個具體的策略對象

     */

    private Strategy strategy = null;

    /**

     * 構造方法,傳入一個具體的策略對象

     * @param aStrategy 具體的策略對象

     */

    public Price(Strategy aStrategy){

       this.strategy = aStrategy;

    }  

    /**

     * 報價,計算對客戶的報價

     * @param goodsPrice 商品銷售原價

     * @return 計算出來的,應該給客戶報的價格

     */

    public double quote(double goodsPrice){

       return this.strategy.calcPrice(goodsPrice);

    }

}

    D:寫個客戶端進行測試

public class Client {

    public static void main(String[] args) {

       //1:選擇並創建需要使用的策略對象

       Strategy strategy = new LargeCustomerStrategy ();

       //2:創建上下文

       Price ctx = new Price(strategy);

       //3:計算報價

       double quote = ctx.quote(1000);

       System.out.println("向客戶報價:"+quote);

    }

}

    2、容錯恢復機制。程式運行的時候,正常情況下應該按照某種方式來做,如果按照某種方式來做發生錯誤的話,系統並不會崩潰,也不會就此不能繼續向下運行了,而是有容忍出錯的能力,不但能容忍程式運行出現錯誤,還提供出現錯誤後的備用方案,也就是恢復機制,來代替正常執行的功能,使程式繼續向下運行。     比如在一個系統中,所有對系統的操作都要有日誌記錄,而且這個日誌還需要有管理界面,這種情況下通常會把日誌記錄在資料庫裡面,方便後續的管理,但是在記錄日誌到資料庫的時候,可能會發生錯誤,比如暫時連不上資料庫了,那就先記錄在文件裡面,然後在合適的時候把文件中的記錄再轉錄到資料庫中。     可以採用策略模式,把日誌記錄到資料庫和日誌記錄到文件當作兩種記錄日誌的策略,然後在運行期間根據需要進行動態的切換。     (1)先定義日誌策略介面,很簡單,就是一個記錄日誌的方法,示例代碼如下:

/**

 * 日誌記錄策略的介面

 */

public interface LogStrategy {

    /**

     * 記錄日誌

     * @param msg 需記錄的日誌信息

     */

    public void log(String msg);

}

    (2)實現日誌策略介面,先實現預設的資料庫實現,假設如果日誌的長度超過長度就出錯,製造錯誤的是一個最常見的運行期錯誤,示例代碼如下:

/**

 * 把日誌記錄到資料庫

 */

public class DbLog implements LogStrategy{

    public void log(String msg) {     

       //製造錯誤

       if(msg!=null && msg.trim().length()>5){

           int a = 5/0;

       }

       System.out.println("現在把 '"+msg+"' 記錄到資料庫中");

    }

}

    接下來實現記錄日誌到文件中去,示例代碼如下: 

/**

 * 把日誌記錄到文件

 */

public class FileLog implements LogStrategy{

    public void log(String msg) {

       System.out.println("現在把 '"+msg+"' 記錄到文件中");

    }

}

    (3)接下來定義使用這些策略的上下文,註意這次是在上下文裡面實現具體策略演算法的選擇,所以不需要客戶端來指定具體的策略演算法了,示例代碼如下:

    (4)看看現在的客戶端,沒有了選擇具體實現策略演算法的工作,變得非常簡單,故意多調用一次,可以看出不同的效果,示例代碼如下:

    參考資料:《Head First 設計模式》               http://www.uml.org.cn/sjms/201009092.asp  
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、簡介Dubbo是Alibaba開源的分散式服務框架,它最 大的特點是按照分層的方式來架構,使用這種方式可以使各個層之間解耦合(或者最大限度地 松耦合)。從服務模型的角度來看,Dubbo採用的是一種非常簡單的模型,要麼是提供方提供服務,要麼是消費方消費服務,所以基於這一點可以抽象出服務提 供方(P ...
  • 觀察者模式:在對象之間定義一對多的依賴,這樣一來,當一個對象改變狀態,依賴它的對象都會收到通知,並自動更新。 舉個例子:氣象監測應用 此系統的三個部分是氣象站(獲取實際氣象數據的物理裝置)、WeatherData對象(追蹤來自氣象站的數據,並更新佈告板)和佈告板(有三個佈告板,一個用來顯示目前天氣狀 ...
  • 新博客 "wossoneri.com" " 設計模式系列目錄 " 需求情景 比如現在需要做一個收銀軟體,要根據用戶所買商品的單價和數量進行計算。 很簡單,用“單價 數量”即可。 但如果某天需要打折呢? 也很簡單,同一個方法,把折扣作為一個參數,預設值為1,代碼改為“單價 數量 折扣”即可。 恩,看起 ...
  • 概述 有時候你可能會在條件判斷中,根據不同的對象類型(通常是基類的一系列子類,或介面的一系列實現),提供相應的邏輯和演算法。當出現大量類型檢查和判斷時,if else(或switch)語句的體積會比較臃腫,這無疑降低了代碼的可讀性。另外,if else(或switch)本身就是一個“變化點”,當需要擴... ...
  • 生成器模式 封裝一個產品的構造過程,並允許按步驟構造。 將一個複雜對象的構建與表示分離,使同樣的構造過程可以創建不同的表示。 生成器模式結構中的四種角色: 產品(Product): 所要構建的複雜對象。 抽象生成器(Builder): 抽象生成器是一個介面,該介面除了為創建一個Product對象的各 ...
  • 適配器模式 適配器模式 將一個類的介面轉換成客戶期望的另一個介面,適配器讓原本介面不相容的類可以合作無間。 通過創建適配器進行介面轉換,讓不相容的介面變成相容。這可以讓客戶從實現的介面解耦。如果在一段時間後,想要改變介面,適配器可以將改變的部分封裝起來,客戶就不必為了應對不同的介面 而每次跟著修改。 ...
  • 狀態模式 允許對象在內部狀態改變時改變它的行為,對象看起來好像修改了它的類。 狀態模式所涉及到的角色有: 環境(Context)角色,也成上下文:定義客戶端所感興趣的介面,並且保留一個具體狀態類的實例。這個具體狀態類的實例給出此環境對象的現有狀態。 抽象狀態(State)角色:定義一個介面,用以封裝 ...
  • 觀察者模式 定義了對象之間的一對多依賴,這樣一來,當一個對象狀態改變時,它的所有依賴者都會收到通知並自動更新。 觀察者模式中,分為推和拉兩種模式。 推模式,即主題對象向觀察者對象推送狀態值,不管觀察者對象是否需要,並且推送全部數據或者部分數據。 拉模式,即主題對象通知觀察者對象狀態值已改變,觀察者根 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...