設計模式-行為型-策略模式

来源:https://www.cnblogs.com/az4215/archive/2019/10/02/11617422.html
-Advertisement-
Play Games

策略模式(Strategy): 策略模式是對演算法的包裝,是把使用演算法的責任和演算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的演算法包裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來說,就是:“準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換”。 策略模式的角色: 1) ...


策略模式(Strategy):

  策略模式是對演算法的包裝,是把使用演算法的責任和演算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的演算法包裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來說,就是:“準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換”。

策略模式的角色:  

  

  1)環境類(Context):採用組合或聚合的方式維護一個對Strategy對象的引用。

  2)抽象策略類(Strategy):定義所有支持的演算法的公共介面。Context使用這個介面來調用某ConcreteStrategy定義的演算法。

  3)具體策略類(ConcreteStrategy):實現Strategy介面。

案例:

  某商場銷售系統採用三種收費邏輯:正常收費;返現收費(滿300返20);打折收費(打8折)。 

 1 internal class Program
 2 {
 3     private static void Main(string[] args)
 4     {
 5         CashContext cashContext = new CashContext(new CashNormal());
 6         Console.WriteLine(cashContext.GetResult(200));
 7         CashContext cashContext2 = new CashContext(new CashRebate(0.8));
 8         Console.WriteLine(cashContext2.GetResult(200));
 9         CashContext cashContext3 = new CashContext(new CashReturn(300, 20));
10         Console.WriteLine(cashContext3.GetResult(300));
11     }
12 }
13 
14 /// <summary>
15 /// 環境類Context
16 /// </summary>
17 public class CashContext
18 {
19     private CashSuper cs;
20 
21     public CashContext(CashSuper cashSuper)
22     {
23         this.cs = cashSuper;
24     }
25 
26     public double GetResult(double money)
27     {
28         if (cs != null)
29         {
30             return cs.AcceptCash(money);
31         }
32         return 0;
33     }
34 }
35 
36 /// <summary>
37 /// 收費系統,相當於Strategy
38 /// </summary>
39 public interface CashSuper
40 {
41     double AcceptCash(double money);
42 }
43 
44 /// <summary>
45 /// 正常收費
46 /// </summary>
47 public class CashNormal : CashSuper
48 {
49     public double AcceptCash(double money)
50     {
51         return money;
52     }
53 }
54 
55 /// <summary>
56 /// 打折收費
57 /// </summary>
58 public class CashRebate : CashSuper
59 {
60     private double moneyRebate = 1d;
61 
62     public CashRebate(double moneyRebate)
63     {
64         this.moneyRebate = moneyRebate;
65     }
66 
67     public double AcceptCash(double money)
68     {
69         return money * moneyRebate;
70     }
71 }
72 
73 /// <summary>
74 /// 返現收費
75 /// </summary>
76 public class CashReturn : CashSuper
77 {
78     private double moneyCondition = 0.0d;
79     private double moneyReturn = 0.0d;
80 
81     public CashReturn(double moneyCondition, double moneyReturn)
82     {
83         this.moneyCondition = moneyCondition;
84         this.moneyReturn = moneyReturn;
85     }
86 
87     public double AcceptCash(double money)
88     {
89         double result = money;
90         if (money >= moneyCondition)
91             result = money - Math.Floor(money / moneyCondition) * moneyReturn;
92         return result;
93     }
94 }

策略模式的優缺點:

  優點:

    1)策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公共的代碼轉移到父類裡面,從而避免重覆的代碼。

    2)策略模式提供了可以替換繼承關係的辦法。繼承可以處理多種演算法或行為。如果不是用策略模式,那麼使用演算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的演算法或行為。但是,這樣一來演算法或行為的使用者就和演算法或行為本身混在一起。決定使用哪一種演算法或採取哪一種行為的邏輯就和演算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變演算法或行為變得不可能。

    3)使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重轉移語句裡面,比使用繼承的辦法還要原始和落後。

  缺點:

    1)客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道所有的演算法或行為的情況。

    2)策略模式造成很多的策略類,每個具體策略類都會產生一個新類。有時候可以通過把依賴於環境的狀態保存到客戶端裡面,而將策略類設計成可共用的,這樣策略類實例可以被不同客戶端使用。換言之,可以使用享元模式來減少對象的數量。

策略模式的應用場景:

  1)一個系統需要動態地在幾種演算法中選擇一種時,可將每個演算法封裝到策略類中。

  2)一個類定義了多種行為,並且這些行為在這個類的操作中以多個條件語句的形式出現,可將每個條件分支移入它們各自的策略類中以代替這些條件語句。

  3)系統中各演算法彼此完全獨立,且要求對客戶隱藏具體演算法的實現細節時。

  4)系統要求使用演算法的客戶不應該知道其操作的數據時,可使用策略模式來隱藏與演算法相關的數據結構。

  5)多個類只區別在表現行為不同,可以使用策略模式,在運行時動態選擇具體要執行的行為。

策略模式與工廠模式的區別?

  從結構上看,策略模式和工廠模式都是子類繼承抽象父類,通過傳入參數到容器類(工廠模式的factory類,策略模式的Content類),選擇對應的類進行行為操作。但是我們都知道工廠模式是創建型設計模式,而策略模式則是行為型設計模式。那兩者到底有什麼區別呢?

  1)工廠模式是用來創建對象,策略模式是讓一個對象在許多行為中選擇一種行為。

  2)關註點不一樣,一個關註對象的創建,一個關註的是行為封裝。

  3)解決不同的問題:工廠模式是創建型的設計模式,它接受指令,創建出符合要求的實例;它主要解決的是資源的統一分發,將對象的創建完全獨立出來,讓對象的創建和具體的使用客戶無關。主要應用在多資料庫選擇,類庫文件載入等。策略模式是為瞭解決的是策略的切換與擴展,更簡潔的說是定義策略族,分別封裝起來,讓他們之間可以相互替換,策略模式讓策略的變化獨立於使用策略的客戶。

  4)工廠相當於黑盒子,策略相當於白盒子。

策略模式與橋接模式的區別?

  在橋接模式中,Abstraction通過聚合的方式引用Implementor。策略模式中,Context也使用聚合的方式引用Strategy抽象介面。從兩者的結構圖可以看出,在這兩種模式中,都存在一個對象使用聚合的方式引用另一個對象的抽象介面的情況,而且該抽象介面的實現可以有多種並且可以替換。可以說兩者在表象上都是調用者與被調用者之間的解耦,以及抽象介面與實現的分離。但兩者存在一定的區別:

  1)在形式上,在橋接模式中不僅Implementor具有變化(ConcreateImplementior),而且Abstraction也可以發生變化(RefinedAbstraction),而且兩者的變化是完全獨立的,RefinedAbstraction與ConcreateImplementior之間鬆散耦合,它們僅僅通過Abstraction與Implementor之間的關係聯繫起來。而在策略模式中,並不考慮Context的變化,只有演算法的可替代性。

  2)在語意上,橋接模式強調Implementor介面僅提供基本操作,而Abstraction則基於這些基本操作定義更高層次的操作。而策略模式強調Strategy抽象介面的提供的是一種演算法,一般是無狀態、無數據的,而Context則簡單調用這些演算法完成其操作。

  3)橋接模式中不僅定義Implementor的介面而且定義Abstraction的介面,Abstraction的介面不僅僅是為了與Implementor通信而存在的,這也反映了結構型模式的特點:通過繼承、聚合的方式組合類和對象以形成更大的結構。在策略模式中,Startegy和Context的介面都是兩者之間的協作介面,並不涉及到其它的功能介面,所以它是行為模式的一種。行為模式的主要特點就是處理的是對象之間的通信方式,往往是通過引入中介者對象將通信雙方解耦,在這裡實際上就是將Context與實際的演算法提供者解耦。

  所以相對策略模式,橋接模式要表達的內容要更多,結構也更加複雜。橋接模式表達的主要意義其實是介面隔離的原則,即把本質上並不內聚的兩種體系區別開來,使得它們可以鬆散的組合,而策略在解耦上還僅僅是某一個演算法的層次,沒有到體系這一層次。從結構圖中可以看到,策略的結構是包容在橋接結構中的,橋接中必然存在著策略模式,Abstraction與Implementor之間就可以認為是策略模式,但是橋接模式一般Implementor將提供一系列的成體系的操作,而且Implementor是具有狀態和數據的靜態結構。而且橋接模式Abstraction也可以獨立變化。

參考:https://blog.csdn.net/donnie88888888/article/details/52751328

  https://blog.csdn.net/basycia/article/details/50478245

  http://www.blogjava.net/wangle/archive/2007/04/25/113545.html


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

-Advertisement-
Play Games
更多相關文章
  • 截圖自:菜鳥教程https://www.runoob.com/jquery/html-outerwidth.html ...
  • 一、路由的配置 路由 vue-router 1. 什麼是路由? 路由相當於一個配置對象 路由:就是我們通過不同的url訪問不同的內容,通過angular.js 可以實現多視圖的單頁,現在流行的單頁面開發模式。 2. 路由在web 有兩種: 第一種 hash hash值前面帶 # " https: / ...
  • js中scroll滾動相關 一.元素相關 | 屬性/方法 | 解釋 | | | | | element.scrollHeight | 返回元素的整體高度。 | | element.scrollWidth | 返回元素的整體寬度。 | | element.scrollLeft | 返回元素左邊緣與視圖 ...
  • Vue 提供了一些不同的過度效果,主要根 v-if v-show 動態組件 1. Vue給動畫分了6個過程,在css中,扮演6個類, 1. .v-enter定義動畫的開始狀態 2. .v-enter-active 定義動畫生效時的狀態 3. .v-enter-to 定義動畫的結束狀態 4. .v-l ...
  • Slot v-slot 插槽元素 瀏覽器在解析時候首先把它當作標簽來解析,只有遇到不認識的就不管了,直接跳過,當你發現是組件,在以組件形式解析。 使用插槽的好處? 比如一個網站 分佈頂部都是一樣的,如果使用組件,要寫好幾個導航組件。我只寫一個導航組件,然後讓插值裡面東西去覆蓋內容 就可以了。 * 在 ...
  • 前兩天遇到的問題,經過很多網友的深刻討論,終於有一個相對可以解釋的通的邏輯了,然後我仔細研究了一下相關的點,順帶研究了一下js中的隱式變數。 以下文章中提到的隱式變數都是指沒有用var,let,const等關鍵字定義的變數。 以下文章中提到的var變數都是指用var聲明定義的變數。 一遇到隱式變數, ...
  • 1.Form標簽:用來將表單外的內容與表單進行關聯。其主要元素有input,button,select。 action屬性:指定表單的發送地址。 Novalidate屬性:數據提交時不校驗。 Target屬性:指定在何處打開指定的url。 method屬性:表單數據發送至伺服器的方法,預設屬性就是g ...
  • 在 HTML 中,JavaScript 語句是由 web 瀏覽器“執行”的“指令”。 實例 var x, y, z; // 語句 1 x = 22; // 語句 2 y = 11; // 語句 3 z = x + y; // 語句 4 JavaScript 程式 電腦程式是由電腦“執行”的一系列 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...