[Architecture] Singleton Locator

組件自己提供Service Locator模式,用來降低組件的耦合度。

[Architecture] Singleton Locator

目的

組件自己提供Service Locator模式,用來降低組件的耦合度。

情景

在開發系統時,底層的Infrastructure Context、或是核心的Domain Context這些共用物件生成之後,會在系統的許多地方被使用。為了減少共用物件初始生成、參考傳遞所造成的困擾,可以在系統內套用Service Locator模式,提供統一的靜態參考點來生成、存取這些共用物件。

Service Locator模式確實減少共用物件初始生成、參考傳遞所造成的困擾,但在實作的過程中卻會發現Service Locator模式,很容易為系統中的組件引入額外相依性。以下列這個範例專案來說,Client物件經由ServiceLocator物件,取得DataContext物件在執行過程中存取資料。

  • 物件圖

    情景02

在實作的過程中為了能夠重用程式碼,通常會將ServiceLocator物件封裝為Infrastructure組件內容,而DataContext物件封裝成為Domain組件內容、Client物件則是封裝為Host組件。

  • 組件圖

    情景03

一般來說Infrastructure組件內會包含許多基礎物件,不會單純只封裝ServiceLocator物件。當這些基礎物件引用其他參考時,也就是間接的增加了Host組件的相依性、增加了Host組件對於其他組件的耦合。

  • 組件圖

    情景04

這時可以考慮將ServiceLocator物件設計為獨立組件,讓組件裡只包含一個物件以避免不必要的相依性。但是當這樣的設計一多的時候,很容易就會讓組件的設計過於破碎。

  • 組件圖

    情景05

為了降低組件耦合的問題,回過頭思考Client物件、DataContext物件、ServiceLocator物件三者之間的關係。會發現Client物件需要的是ServiceLocator物件所提供的物件生成、靜態參考等功能,而不是真的需要一個ServiceLocator物件。

這時開發人員可以將ServiceLocator物件所提供的物件生成、靜態參考等功能,建立在DataContext物件自己本身之上,透過DataContext物件自己提供物件生成、靜態參考等功能。也就是說經由這樣的設計,將ServiceLocator物件從系統中移除、也就是把Infrastructure組件從系統中移除,進而降低了Host組件的相依性、降低了Host組件對於其他組件的耦合。

  • 組件圖

    情景06

結構

  • 物件圖

    結構01

參與者

Service

  • 提供自身服務功能。

  • 提供自身靜態參考,用於參考定位、外部生成。

  • 提供自身生成功能,用於內部生成。

Client

  • 使用Context功能的物件。

  • 外部生成的使用情景中,生成Context並且注入Context靜態參考。

合作方式

  • 外部生成

    合作方式01

  • 內部生成

    合作方式02

(為了簡化說明,Service生成模式採用直接建立的方式來示意。實際專案可以採用各種IoC Framework來做生成注入,或是套用各種Factory pattern,這些都能提高Service的重用性。)

實作

  • 類別圖

    實作01

  • Service

    public partial class Service
    {
        // Locator
        private static Service _current;
    
        public static Service Current
        {
            get
            {
                if (_current == null)
                {
                    _current = new Service("內部生成");
                }
                return _current;
            }
            set
            {
                _current = value;
            }
        }
    }
    
    public partial class Service
    {
        // Constructors
        public Service(string message)
        {
            // Arguments
            this.Message = message;
        }
    
    
        // Properties
        public string Message { get; set; }
    
    
        // Methods
        public void Execute()
        {
            Console.WriteLine(this.Message);
        }
    }
    
  • 外部生成

    class Program
    {
        static void Main(string[] args)
        {
            // Init
            Init();
    
            // Execute
            Service.Current.Execute();
            Console.WriteLine();
    
            // End           
            Console.WriteLine("End...");
            Console.ReadLine();
        }
    
        static void Init()
        {
            // Service
            Service.Current = new Service("外部生成");
        }
    }
    

    實作02

  • 內部生成

    class Program
    {
        static void Main(string[] args)
        {
            // Init
            Init();
    
            // Execute
            Service.Current.Execute();
            Console.WriteLine();
    
            // End           
            Console.WriteLine("End...");
            Console.ReadLine();
        }
    
        static void Init()
        {
            // Service
    
        }
    }
    

    實作03

(為了簡化說明,Service生成模式採用直接建立的方式來示意。實際專案可以採用各種IoC Framework來做生成注入,或是套用各種Factory pattern,這些都能提高Service的重用性。)

下載

範例程式碼:點此下載

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。