好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Service Locator

[Architecture Pattern] Service Locator

动机

Service Locator是一个在开发系统时,很常用的一个模式。在Martin Fowler写的Inversion of Control Containers and the Dependency Injection pattern里,可以发现这个Pattern的身影。Service Locator最主要是定义BLL层内对象生成、对象存放、对象取得的职责,让系统在取得对象时不需要知道对象是如何生成及存放,有效降低系统的耦合性。

同时学习Service Locator,也为架构设计带入了空间的概念。在设计架构的时候,可以套用Service Locator来做为架构空间的封装。将经对象生成建立的对象,「存放」在Service Locator内,让目标架构「存在」一组对象可以提供使用。

本篇文章介绍一个Service Locator的实做,这个实做定义对象之间的职责跟互动,用来完成Service Locator应该提供的功能及职责。为自己做个纪录,也希望能帮助到有需要的开发人员。

结构

接下来沿用[Architecture Pattern] Repository建立的UserCountService,来当作范例的内容。另外在BLL层使用Service Locator来封装UserCountService的对象生成、对象存放、对象取得。范例的结构如下:

主要的参与者有:

ServiceLocator
-提供存放对象的功能给系统使用。
-提供存放的对象给系统使用。

Client
-使用ServiceLocator内存放的UserCountService。

UserCountService
-使用系统内User数据计算各种Count。
-由Client生成或是ServiceLocator生成。

透过下面的图片说明,可以了解相关对象之间的互动流程。



实做

Service Locator由两种运作逻辑所组成:定位逻辑、生成逻辑。定位逻辑是整个Service Locator的核心,它定义对象存放、对象取得的职责。而对象必须要被生成才能够使用,生成逻辑就是定义对象生成的职责。接着透过实做一组Service Locator,解析Service Locator内的运作逻辑,帮助开发人员理解Service Locator模式。

范列下载

实做说明请参照范例程序内容: ServiceLocatorSample点此下载

定位逻辑

首先建立ServiceLocatorSample.BLL项目,并且建立ServiceLocator对象用来封装Service Locator的定位逻辑:ServiceLocator提供SetInstance方法,让系统可以存放各种型别的对象。并且ServiceLocator提供GetInstance方法,让系统可以取得先前存放的对象。

?

public partial class ServiceLocator

{

     // Fields 

     private readonly Dictionary<Type, object > _serviceDictionary = new Dictionary<Type, object >();

 

 

     // Methods

     public TService GetInstance<TService>() where TService : class

     {

         // Result

         TService service = default (TService);

 

         // Exist

         if (_serviceDictionary.ContainsKey( typeof (TService)) == true )

         {

             service = _serviceDictionary[ typeof (TService)] as TService;

         }

 

         // Return

         return service;

     }

 

     public void SetInstance<TService>(TService service) where TService : class

     {

         #region Require

 

         if (service == null ) throw new ArgumentNullException();

 

         #endregion

 

         // Set

         if (_serviceDictionary.ContainsKey( typeof (TService)) == false )

         {

             _serviceDictionary.Add( typeof (TService), service);

         }

         else

         {

             _serviceDictionary[ typeof (TService)] = service;

         }

     }

}

另外ServiceLocator也套用了Singleton pattern,让系统能方便的使用ServiceLocator。

?

public partial class ServiceLocator

{

     // Singleton

     private static ServiceLocator _current;

 

     public static ServiceLocator Current

     {

         get

         {

             if (_current == null )

             {

                 _current = new ServiceLocator();

             }

             return _current;

         }

         set

         {

             _current = value;

         }

     }

}

外部生成逻辑

再来建立一个Console项目,透过ServiceLocator取得UserCountService用来打印的人员数量。而UserCountService是由Console专案来生成、注入ServiceLocator。

?

class Program

{

     static void Main( string [] args)

     {

         // Initialize

         InitializeServiceLocator();

              

         // UserCountService

         UserCountService userCountService = ServiceLocator.Current.GetInstance<UserCountService>();

 

         // Print

         Console.WriteLine( "All Count : " + userCountService.GetAllCount());

         Console.WriteLine( "Men Count : " + userCountService.GetMenCount());

 

         // End

         Console.ReadLine();

     }

 

     static void InitializeServiceLocator()

     {

         // UserRepository

         IUserRepositoryProvider userRepositoryProvider = new SqlUserRepositoryProvider();

         UserRepository userRepository = new UserRepository(userRepositoryProvider);

         UserCountService userCountService = new UserCountService(userRepository);

 

         // SetInstance

         ServiceLocator.Current.SetInstance<UserCountService>(userCountService);

     }

}

内部生成逻辑

到目前为止范例程序,已经可以透过ServiceLocator取得UserCountService用来打印的人员数量。但UserCountService是由ServiceLocator之外的函式来生成、存放至ServiceLocator。这造成每次重用的时候,必须要重新建立对象生成、存放的功能。

为了增加ServiceLocator的重用性,所以修改ServiceLocator对象,封装Service Locator的生成逻辑:ServiceLocator提供CreateInstance方法,让系统可以建立各种型别的对象。并且变更GetInstance的运作流程,让系统取不到先前存放的对象时,会去使用CreateInstance来生成对象。

(因为是仿真范例,简化了很多UserCountService的设计,并且采用直接建立的方式来示意。实际项目可以采用各种IoC Framework来做生成注入,或是套用各种Factory pattern,这些都能提高ServiceLocator的重用性。)

?

public partial class ServiceLocator

{

     // Fields 

     private readonly Dictionary<Type, object > _serviceDictionary = new Dictionary<Type, object >();

 

 

     // Methods

     protected virtual TService CreateInstance<TService>() where TService : class

     {

         // Result

         TService service = default (TService);

 

         // UserCountService

         if ( typeof (TService) == typeof (UserCountService))

         {

             IUserRepositoryProvider userRepositoryProvider = new CsvUserRepositoryProvider();

             UserRepository userRepository = new UserRepository(userRepositoryProvider);

             UserCountService userCountService = new UserCountService(userRepository);

             service = userCountService as TService;

         }

 

         // Return

         return service;

     }

 

     public TService GetInstance<TService>() where TService : class

     {

         // Result

         TService service = default (TService);

 

         // Exist

         if (_serviceDictionary.ContainsKey( typeof (TService)) == true )

         {

             service = _serviceDictionary[ typeof (TService)] as TService;

         }

         if (service != null ) return service;

 

         // Create

         service = this .CreateInstance<TService>();

         if (service != null ) this .SetInstance<TService>(service);

 

         // Return

         return service;

     }

 

     public void SetInstance<TService>(TService service) where TService : class

     {

         #region Require

 

         if (service == null ) throw new ArgumentNullException();

 

         #endregion

 

         // Set

         if (_serviceDictionary.ContainsKey( typeof (TService)) == false )

         {

             _serviceDictionary.Add( typeof (TService), service);

         }

         else

         {

             _serviceDictionary[ typeof (TService)] = service;

         }

     }

}

最后修改Console项目,移除项目内生成UserCountService的逻辑。并且同样透过ServiceLocator取得UserCountService用来打印的人员数量。

?

class Program

{

     static void Main( string [] args)

     {

         // UserCountService

         UserCountService userCountService = ServiceLocator.Current.GetInstance<UserCountService>();

 

         // Print

         Console.WriteLine( "All Count : " + userCountService.GetAllCount());

         Console.WriteLine( "Men Count : " + userCountService.GetMenCount());

 

         // End

         Console.ReadLine();

     }

}

后记

Service Locator有很多实做版本,这些实做版本依照需求分割、设计,BLL层内对象生成、对象存放、对象取得的职责,用以提高整体架构的重用性、可维护性。一个系统的成败,除了最基本的满足客户需求之外,这些额外的非功能需求也是很重要的一环。这让后续接手维护的开发人员,能够早点回家吃晚餐。:D

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

分类:  Architecture Pattern

作者: Leo_wl

    

出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Service Locator的详细内容...

  阅读:46次

上一篇: C#网络编程

下一篇:RestSharp使用详解