幾種常見設計模式在項目中的應用<Singleton、Factory、Strategy>

  • 2019 年 12 月 16 日
  • 筆記

一、前言

  前幾天閱讀一框架文檔,裏面有一段這樣的描述 「從對象工廠中………」 ,促使寫下本文。儘管一些模式簡單和簡單,但是常用、有用。

  結合最近一個項目場景回顧一下裏面應用到的一些模式<Singleton、Factory、Strategy>。

  Singleton:創建型模式,負責創建維護一個全局唯一實例

  Factory:創建型模式,對象工廠負責根據標識創建或獲取具體的實例對象

  Strategy:行為型/運行時模式,策略負責根據標識控制應用運行時的行為

示例代碼:https://github.com/Shawn-china/DesignPatternDemo.git

二、場景上下文

  項目需求/場景:通過增加輔助工具使用腳本程序對特定應用程序進行「自動化測試」,內容包括:點擊按鈕、選擇菜單、讀取控件內容等。

  原始實現:腳本程序<AutoIt>通過計算坐標的方式對特定應用程序進行「自動化測試」。缺點:腳本程序工作量大、依賴按鈕屏幕坐標、坐標計算繁雜、依賴屏幕分辨率等。

  目標程序簡化圖:

圖1 目標程序

  使用輔助工具前 :

圖2 未使用輔助工具

  使用輔助工具後:

圖3 使用輔助工具

三、分析、設計 

  這裡只對 輔助工具 進行分析設計,其它略過。

  1、圖1 目標程序有以下主要特點:

    • 目標程序分為 A-E五個功能區

    • 每個功能區有按鈕、菜單等相似功能

    • 每個功能區有特有功能

  2、輔助工具對外提供統一調用

  3、輔助工具可以被重複調用,但不支持並發操作

  基於以上分析:

    1、將 Operator <操控代碼或具體操控行為>分為五個具體的 Operator 分別為:AOperator 、BOperator 、COperator 、DOperator 、EOperator ,分別對應操作不同的應用程序區域。

    2、使用創建型模式管理 Operator

    3、使用鎖機制,限制並發

    4、外層封裝一個單例

四、UML  

圖4 UML類圖

五、Code Show

  1、AuxiliaryToolSingleton 對外提供調用,並用鎖機制控制並發。

using System;  using System.Threading;  using DesignPatternDemo.Operator;    namespace DesignPatternDemo  {      public class AuxiliaryToolSingleton      {          public static Semaphore OperatorSemaphore = new Semaphore(1, 1);          private static readonly object OperatorLock = new object();            public static AuxiliaryToolSingleton Instance = new AuxiliaryToolSingleton();          private AuxiliaryToolSingleton()          {              RegistorOperator(OperatorFactory.Instance);          }            public void CallOperator(string operatorName, params string[] operatorParams)          {              //OperatorSemaphore.WaitOne();              lock (OperatorLock)              {                  Console.WriteLine($"Call method CallOperator :{operatorName} .Current Thread:{Thread.CurrentThread.ManagedThreadId}");                    BaseOperator concreteOperator = OperatorFactory.Instance.GetOperator(operatorName);                  concreteOperator.InitializationParameters(operatorParams);                  concreteOperator.Execute();              }                //OperatorSemaphore.Release();          }            public static void RegistorOperator(OperatorFactory factory)          {              factory.Register(nameof(AOperator), new AOperator());              factory.Register(nameof(BOperator), new BOperator());              factory.Register(nameof(COperator), new COperator());              factory.Register(nameof(DOperator), new DOperator());              factory.Register(nameof(EOperator), new EOperator());          }      }  }

2、BaseOperator 操控基類,包含一些公共方法、虛方法、參數信息。

using System;  using System.Threading;    namespace DesignPatternDemo.Operator  {      public class BaseOperator      {          public string Name { get; set; }          public string Description { get; set; }            public void Execute()          {              //ToDo              Thread.Sleep(new Random().Next(0, 5) * 1000);              Console.WriteLine($"Execute concrete operator:{GetType().Name} .Current Thread:{Thread.CurrentThread.ManagedThreadId}");              ConcreteOperate($"{GetType().Name}");          }          public void InitializationParameters(params string[] operatorParams)          {              //ToDo                Console.WriteLine($"Initialization Parameters :{GetType().Name}");          }          private void ConcreteOperate(string mark)          {              // ToDo              Console.WriteLine($"The concrete operation :{mark} was performed successfully .rn");          }          public virtual void ClickButtonByMark(string mark)          {              // ToDo              ConcreteOperate(mark);          }            public virtual void ClickPopupMenuByMark(string mark)          {              // ToDo              ConcreteOperate(mark);          }            public virtual void SelectDropdownBoxByIndex(int dropBoxIndex)          {              // ToDo              ConcreteOperate($"{dropBoxIndex}");          }      }  }  

3、AOperator 具體操控類<比如點擊按鈕>,實現ISpecialOperateA, 繼承BaseOperator 。

using System;    namespace DesignPatternDemo.Operator  {      public class AOperator : BaseOperator, ISpecialOperateA      {          public void SetContent(string content)          {              //ToDo              Console.WriteLine($"Filled the content:{content} successfully");          }          public string GetContent()          {              //ToDo              return $"{new Random().Next()}{Guid.NewGuid()}";          }      }  }    namespace DesignPatternDemo.Operator  {      public interface ISpecialOperateA      {          void SetContent(string content);          string GetContent();      }  }  

4、BOperator 、COperator 、DOperator 具體操控類

namespace DesignPatternDemo.Operator  {      public class BOperator : BaseOperator      {      }  }    namespace DesignPatternDemo.Operator  {      public class COperator : BaseOperator      {      }  }    namespace DesignPatternDemo.Operator  {      public class DOperator : BaseOperator      {      }  }

5、EOperator 具體操控類<比如操控樹形控件>,實現ISpecialOperateE, 繼承BaseOperator 。

using System;    namespace DesignPatternDemo.Operator  {      public class EOperator : BaseOperator, ISpecialOperateE      {          public void ClickTreeviewByMark(string mark)          {              //ToDo              Console.WriteLine($"{mark}: execution succeed");          }      }  }    namespace DesignPatternDemo.Operator  {      public interface ISpecialOperateE      {          void ClickTreeviewByMark(string mark);      }  }  

6、Factory 工廠類基類,可根據key註冊、刪除、獲取具體類。創建型模式的一種。

using System.Collections.Generic;    namespace DesignPatternDemo  {      public class Factory<TF, TV> where TF : new()      {          protected Factory()          {              KeyValues = new Dictionary<string, TV>();          }            public static TF Instance { get; set; } = new TF();            private Dictionary<string, TV> KeyValues { get; }            public TV GetItem(string key)  {              KeyValues.TryGetValue(key, out TV find);                return find;          }          public void Register(string key, TV t)  {              UnRegister(key);              KeyValues.Add(key, t);          }            public void UnRegister(string key)  {              if (KeyValues.ContainsKey(key)) KeyValues.Remove(key);          }      }  }

7、OperatorFactory 具體工廠,繼承Factory 。

using DesignPatternDemo.Operator;    namespace DesignPatternDemo  {      public class OperatorFactory : Factory<OperatorFactory, BaseOperator>      {          public BaseOperator GetOperator(string operatorName)  {              return GetItem(operatorName);          }      }  }

8、Program 控制台程序,分別使用並行庫和Task 多線程調用模擬。

using System;  using System.Collections.Generic;  using System.Threading.Tasks;  using DesignPatternDemo.Operator;    namespace DesignPatternDemo  {      internal class Program      {          private static void Main(string[] args)          {              Console.WriteLine("Hello World!");                List<string> concreteOperators = GetConcreteOperators();                Parallel.ForEach(concreteOperators, current => { CallOperator(current); });                foreach (string operatorName in concreteOperators)              {                  Task concreteTask = new Task(() => { CallOperator(operatorName); });                  concreteTask.Start();              }                Console.ReadKey();          }          private static List<string> GetConcreteOperators()          {              List<string> concreteOperators = new List<string>              {                  nameof(AOperator),                  nameof(BOperator),                  nameof(COperator),                  nameof(DOperator),                  nameof(EOperator)              };              return concreteOperators;          }            private static void CallOperator(string operatorName, params string[] operatorParams)          {              AuxiliaryToolSingleton auxiliaryTool = AuxiliaryToolSingleton.Instance;              auxiliaryTool.CallOperator(operatorName, operatorParams);          }      }  }

六、說明、小結

  1、本文只是為了說明回顧一些模式的使用、原始項目的業務、代碼結構、實現語言均作了更換或簡化。

  2、UML 所描述,可以使用任何OO語言實現。

  3、如果條件判斷很多可以使用:「表驅動法」、Strategy pattern 規避。

  4、模式套路與之相應的場景。

  5、Demo 代碼環境:vs2017 .Net Core2.2