熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

C# Design Patterns (2) - 

2022-06-13   來源: .NET編程 

  Strategy Pattern (策略模式)

  所謂 Strategy Pattern 的精神就是將策略 (算法) 封裝為一個對象易於相互替換如同 USB 設備一樣可即插即用而不是將策略具體的算法和行為硬編碼在某個類或客戶程序中導至事後的修改和擴展不易

  若有多種「策略」就將這些個策略和這些策略的算法行為封裝在各個類中並讓這些類去繼承某個公用的抽象類或接口接著在客戶程序中就可動態引用且易於更換這些不同的「策略」不會因為日後添加修改了某一個「策略」就得重新修改編譯多處的源代碼此即為一種「封裝變化點」的做法將常會變化的部分進行抽象定義為接口亦即實現「面向接口編程」的概念且客戶程序 (調用者) 只須知道接口的外部定義即可具體的實現則無須理會

  The Strategy Pattern defines a family of algorithms encapsulates each one and makes them interchangeable Strategy lets the algorithm vary independently from clients that use it

  - Design Patterns: Elements of Reusable ObjectOriented Software

  Strategy Pattern 適用的情景

  應用中的許多類在解決某些問題時很相似但實現的行為有所差異比如不同功能的程序都可能要用到「排序」算法

  根據運行環境的不同需要采用不同的算法比如在手機PC 計算機上因硬件等級不同必須采用不同的排序算法

  針對給定的目的存在多種不同的算法且我們可用代碼實現算法選擇的標准

  需要封裝復雜的數據結構比如特殊的加密算法客戶程序僅需要知道調用的方式即可

  同上算法中的羅輯和使用的數據應該與客戶程序隔離時

   

  圖  這張為很多書籍和文檔都曾出現過的 Strategy 經典 Class Diagram

  _Shellaspxcs

  using System;

  using blogsWizardWusample;

  //客戶程序

  public partial class __Shell : SystemWebUIPage

  {

  protected void Page_Load(object sender EventArgs e)

  {

  //執行對象

  Context context;

  context = new Context(new ConcreteStrategyA());

  ResponseWrite(contextContextInterface() +

  );

  context = new Context(new ConcreteStrategyB());

  ResponseWrite(contextContextInterface() +

  );

  context = new Context(new ConcreteStrategyC());

  ResponseWrite(contextContextInterface() +

  );

  }

  }

  namespace blogsWizardWusample

  {

  //抽象算法類 (亦可用接口)定義了所有策略的公共接口

  abstract class Strategy

  {

  //算法需要完成的功能

  public abstract string AlgorithmInterface();

  }

  //具體算法類A

  class ConcreteStrategyA : Strategy

  {

  //算法A實現方法

  public override string AlgorithmInterface()

  {

  return 算法A實現;

  }

  }

  //具體算法類B

  class ConcreteStrategyB : Strategy

  {

  //算法B實現方法

  public override string AlgorithmInterface()

  {

  return 算法B實現;

  }

  }

  //具體算法類C

  class ConcreteStrategyC : Strategy

  {

  //算法C實現方法

  public override string AlgorithmInterface()

  {

  return 算法C實現;

  }

  }

  //執行對象需要采用可替換策略執行的對象

  class Context

  {

  Strategy strategy;

  public Context(Strategy strategy)        //構造函數

  {

  thisstrategy = strategy;

  }

  //執行對象依賴於策略對象的操作方法

  public string ContextInterface()

  {

  return strategyAlgorithmInterface();

  }

  }

  } // end of namespace

  /*

  結行結果:

  算法A實現

  算法B實現

  算法C實現

  */

  上方的「Shell (殼)」示例中最下方的 Context 類為一種維護上下文信息的類讓 Strategy 類 (或 IStrategy 接口) 及其子類對象的算法能運行在這個上下文裡

  下方的圖 及其代碼為此 Shell 示例和 Strategy Pattern 的一個具體實現示例我們知道Linux 和 Windows 操作系統在文本文件的「換行符」是不同的前者為「\n」後者為「\r\n」若我們要設計一個文本編輯工具或簡易的編程工具必須要能隨時轉換這兩種不同操作系統的換行符 (假設 NET 已可執行於 Linux 上)此時我們即不該在客戶程序 (如ASPNET 頁面的 CodeBehind) 中用硬編碼 switchcase 的 hard coding 寫法而應如下方示例以 Strategy Pattern 實現此一功能並將這些算法 (策略) 各自封裝在各個子類中 (如 ASPNET 項目的 App_Code 文件夾中的類或其他類庫項目中的類)使他們易於組合更換便於日後的維護和修改

  圖  示例  _Strategyaspxcs 的 Class Diagram此為 Sybase PowerDesigner 的「Reverse Engineer」功能所自動產生的圖

  _Strategyaspxcs

  using System;

  using blogsWizardWusample;

  //客戶程序

  public partial class __Strategy : SystemWebUIPage

  {

  String strLinuxText = 操作系統 \n 紅帽 Linux  創建的 \n 文本文件;

  String strWindowsText = 操作系統 \r\n 微軟 Windows 創建的 \r\n 文本文件;

  protected void Page_Load(object sender EventArgs e)

  {

  }

  protected void DropDownList_SelectedIndexChanged(object sender EventArgs e)

  {

  switch(DropDownListSelectedValue)

  {

  case Linux:

  LabelText = CntextInterface(new LinuxStrategy(strWindowsText));

  //LabelText = strWindowsTextReplace(\r\n \n);   //未用任何 Pattern 的寫法

  break;

  case Windows:

  LabelText = CntextInterface(new WindowsStrategy(strLinuxText));

  //LabelText = strLinuxTextReplace(\n \r\n);   //未用任何 Pattern 的寫法

  break;

  default:

  LabelText = StringEmpty;

  break;

  }

  }

  }

  namespace blogsWizardWusample

  {

  //抽象算法類 (亦可用接口)定義了所有策略的公共接口

  public abstract class TextStrategy

  {

  protected String text;

  public TextStrategy(String text)           //構造函數

  {

  thistext = text;

  }

  //算法需要完成的功能

  public abstract String replaceChar();

  }

  //具體算法類A

  public class LinuxStrategy : TextStrategy

  {

  public LinuxStrategy(String text)          //構造函數

  : base(text)

  {

  }

  //算法A實現方法

  public override String replaceChar()

  {

  text = textReplace(\r\n \n);

  return text;

  }

  }

  //具體算法類B

  public class WindowsStrategy : TextStrategy

  {

  public WindowsStrategy(String text)     //構造函數

  : base(text)

  {

  }

  //算法B實現方法

  public override String replaceChar()

  {

  text = textReplace(\n \r\n);

  return text;

  }

  }

  //執行對象需要采用可替換策略執行的對象

  public class ContextCharChange

  {

  //執行對象依賴於策略對象的操作方法

  public static String contextInterface(TextStrategy strategy)

  {

  return strategyreplaceChar();

  }

  }

  } // end of namespace

   

  圖  示例 _Strategyaspxcs 的執行結果

  若未用任何 Pattern 的客戶程序可能就如下方的硬編碼將「換行符」和算法直接寫死在 ASPNET 的 CodeBehind 裡導至事後的維護和擴展不易

  hard coding

  protected void DropDownList_SelectedIndexChanged(object sender EventArgs e)

  {

  switch(DropDownListSelectedValue)

  {

  case Linux:

  LabelText = strWindowsTextReplace(\r\n \n);

  break;

  case Windows:

  LabelText = strLinuxTextReplace(\n \r\n);

  break;

  default:

  LabelText = StringEmpty;

  break;

  }

  }

  此外若用 Simple Factory Pattern (簡單工廠模式) 雖然也能解決上述硬編碼的問題但就如我們前一篇帖子「C# Design Patterns () Factory Method」曾經提過的缺點日後若要添加或修改功能時仍要修改重新編譯 serverside 的「工廠類」所以在此種情況下用 Strategy 會是比 Simple Factory 更好的選擇

  

  Strategy Pattern 的優點

  簡化了單元測試因為每個算法都有自己的類可以通過自己的接口單獨做測試

  避免程序中使用多重條件轉移語句使系統更靈活並易於擴展

  高內聚低偶合

  Strategy Pattern 的缺點

  因為每個具體策略都會產生一個新類所以會增加需要維護的類的數量

  選擇所用具體實現的職責由客戶程序承擔並轉給 Context 對象並沒有解除客戶端需要選擇判斷的壓力

  若要減輕客戶端壓力或程序有特殊考量還可把 Strategy 與 Simple Factory 兩種 Pattern 結合即可將選擇具體算法的職責改由 Context 來承擔亦即將具體的算法和客戶程序做出隔離有關這方面的概念和示例可參考伍迷的「大話設計模式」一書 []

  

  此外從行為上來看State Pattern 和 Strategy Pattern 有點類似但前者可看作後者的動態版本

  State看當前是什麼狀態就采取什麼動作

  Strategy看需求及情景為何采用適當的策略

  State 中當對象內部的狀態改變時它可切換到一組不同的操作從而改變對象的行為例如 GoF 示例中的 TCP 連接而 Strategy 是直接采用適當的策略 (算法)如本帖示例中不同的操作系統實現換行的具體算法類 LinuxStrategy 與 WindowsStrategy


From:http://tw.wingwit.com/Article/program/net/201311/12743.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.