設計模式學習歷程(二)————從簡單工廠到策略模式

来源:http://www.cnblogs.com/blueeyeswhitedragon/archive/2016/07/29/5718629.html
-Advertisement-
Play Games

學習完了簡單工廠模式以後,感覺可以用於解決大多數多演算法選擇的問題了,接下來看一個新的例子,也是借用《大話數據結構》一書的例子,要實現的是一個商場促銷的計算軟體,輸入商品的單價和數量,還有銷售策略(如打折,返現),然後計算出總的價格。 首先可以從這個問題中抽象出兩個演算法類,一個是打折演算法類,需要提供打 ...


  學習完了簡單工廠模式以後,感覺可以用於解決大多數多演算法選擇的問題了,接下來看一個新的例子,也是借用《大話數據結構》一書的例子,要實現的是一個商場促銷的計算軟體,輸入商品的單價和數量,還有銷售策略(如打折,返現),然後計算出總的價格。

  首先可以從這個問題中抽象出兩個演算法類,一個是打折演算法類,需要提供打折的幅度,如八折,另一個是返現演算法類,需要提供返現的最小額度和返現金額,如滿300減100,它們都有一個共同的方法,計算出總的價格,這裡因為每個類裡面只有一個計算總價的方法需要用到金額,所以可以直接把總金額作為函數的參數傳入,而不用作為演算法類的成員變數,用簡單工廠模式實現如下:

 1 class Collection
 2 {
 3 public:
 4     virtual float GetSum(float money) { return money; }
 5     virtual ~Collection() {}
 6 };
 7 class CollectionDiscount :public Collection
 8 {
 9 private:
10     float discount = 1.0f;
11 public:
12     CollectionDiscount() = default;
13     CollectionDiscount(float d):discount(d){}
14     float GetSum(float money) override
15     {
16         return money*discount;
17     }
18 };
19 class CollectionReturn :public Collection
20 {
21 private:
22     float limit=0.0f;
23     float value = 0.0f;
24 public:
25     CollectionReturn() = default;
26     CollectionReturn(float l,float v) :limit(l),value(v) {}
27     float GetSum(float money) override
28     {
29         if (money >= limit)
30             return money - value;
31         else
32             return money;
33     }
34 };
35 class CollectionFactory
36 {
37 public:
38     static shared_ptr<Collection> CreateCollection(string type)
39     {
40         shared_ptr<Collection> ptr = nullptr;
41         if (type == "打八折")
42             ptr = make_shared<CollectionDiscount>(0.8);
43         else if (type == "滿300送100")
44             ptr= make_shared<CollectionReturn>(300, 100);
45         else
46             throw(invalid_argument("沒有這種折扣策略"));
47         return ptr;
48     }
49 };

1 int main()
2 {
3     shared_ptr<Collection> c = CollectionFactory::CreateCollection("打八折");
4     cout << c->GetSum(100) << endl;
5     return 0;
6 }

 

 

 

  這樣工廠類的對象就可以通過輸入的字元串來判斷,並生成對應的演算法類的對象,最後客戶端就能調用演算法類中的方法進行計算了,簡單工程模式很好的解決的了對象的創建問題,但是有一個問題就是演算法類的名稱還是出現在了客戶端程式中,那麼對於大型商場而言,它的銷售策略千奇百怪,總會出現很多新的銷售策略演算法,那麼有沒有一種模式,能完全不讓演算法類的名字出現在客戶端程式。面對這種演算法時常變動,可以採用策略模式。

  策略模式就是定義了演算法家族,將它們分別封裝起來,讓它們之間可以相互替換,可以讓演算法變化,但是不會影響到使用演算法的客戶。在這個例子裡面前面兩個演算法類的內容都不需要修改,僅僅需要修改的就是將工廠類改為一個上下類,用上下文類來管理演算法對象,同時這裡為了將判斷程式寫在業務邏輯裡面,所以將策略模式和簡單工廠可以結合如下:

 1 class Context//以對象管理演算法資源
 2 {
 3 private:
 4     Collection *pCollection=nullptr;
 5 public:
 6     Context() = default;
 7     Context(string type)
 8     {
 9         if (type == "打八折")
10             pCollection = new CollectionDiscount(0.8);
11         else if (type == "滿300返100")
12             pCollection = new CollectionReturn(300, 100);
13         else
14             throw(invalid_argument("沒有這種折扣策略"));
15     }
16     float ContextInterface(float money)
17     {
18         return pCollection->GetSum(money);
19     }
20     ~Context() { delete pCollection; }
21 };
1 int main()
2 {
3     Context context("打八折");
4     cout << context.ContextInterface(100) << endl;
5     return 0;
6 }

 

  可以發現上下文類主要做的修改就是,它擁有一個指向一個演算法對象的指針成員變數,也就是說,完全可以在這個類裡面執行演算法運算,然後再把結果傳輸給用戶,然後因為指針是類的成員變數,所以可以很方便的在這個類的析構函數裡面將這個指針所指對象銷毀,就沒沒必要用到智能指針,也使得整個客戶端代碼簡潔明瞭了不少,最後我們也可以神奇地發現客戶端代碼裡面完全沒有出現演算法類,僅僅只出現了上下文類,使得演算法與客戶端完全分離了。

  最後總結一下,策略模式定義了一系列演算法的方法,所有演算法都是完成了相同的工作,僅僅是實現不同,它可以通過上下文類以相同的方式調用所有的演算法,最重要的一點就是減少了演算法類和實用演算法類之間的耦合。那什麼時候用策略模式呢,策略模式就是用來封裝演算法的,但在實踐中,可以用它來封裝幾乎任何類型的規則,主要在分析過程中聽到需要不同時間,應用不同的業務規則,就可以考慮用策略模式處理這種變化的可能性。

  最後一句,任何需求的變更都是需要成本的,整個程式員之路也是路漫漫其修遠兮。


 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、位運算符 位運算符用來對整型數的指定位進行置位,如果被操作數是字元串,則對該字元串的ASCII碼值進行操作。 2、遞增遞減運算符 3、三元運算符 三元運算符(?:),又稱三目運算符,作用類似選擇語句,用於根據一個表達式的真假,從另外兩個表達式中選擇一個。用法如下: 邏輯表達式 ? 表達式1 : ...
  • 反射:java.lang.reflect 要被載入的類: 載入運行的類: 輸出的結果: Program start.loading WaitingforLoaderConstructor of WaitingforLoader without anything.Constructor of Wait ...
  • 運行結果: 60SundaySundayTuesdayWednesdaytrue7MondayTuesdayWednesdayThursadyFridaySaturdaySunday ...
  • 1. 併發:在操作系統中,是指一個時間段中有幾個程式都處於已啟動運行到運行完畢之間,且這幾個程式都是在同一個處理機上運行。其中兩種併發關係分別是同步和互斥 2. 互斥:進程間相互排斥的使用臨界資源的現象,就叫互斥。 3. 同步:進程之間的關係不是相互排斥臨界資源的關係,而是相互依賴的關係。進一步的說 ...
  • 發大水 ...
  • 在上一節中,我們已經創建了一個Django模型Post,並使Post模型與資料庫同步。這一節中,我們將介紹Django管理站點,通過Django管理站點來管理我們創建的Post模型實例。 為你的模型創建一個控制管理站點 好了,我們已經定義了一個post模型,現在,我們將要創建一個簡單的管理站點,來管 ...
  • 類是組成java程式的基本要素,是java中的一種重要的複合數據類型。它封裝了一類對象的狀態和方法,是這一類對象的原型。一個類的實現包括兩個部分:類聲明和類體,基本格式: class <class name> { 屬性 方法 } 其中,class是關鍵字,用來定義類。“class <class na ...
  • 1.背景 1.1.範圍 MODBUS 是 OSI 模型第 7 層上的應用層報文傳輸協議, 它在連接至不同類型匯流排或網路的設備之間提供客戶機/伺服器通信。 自從 1979 年出現工業串列鏈路的事實標準以來, MODBUS 使成千上萬的自動化設備能夠通信。 目前,繼續增加對簡單而雅觀的 MODBUS 結 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...