zoukankan      html  css  js  c++  java
  • [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实做看来下,眼尖的开发人员会发现,它跟IoC Framework有异曲同工的意味。Service Locato跟IoC Framework的差异,主要是在:IoC Framework的主要职责是对象生成,Service Locator的主要职责是对象存放、对象取得。只是发展到了后来,两者几乎都实做了对象生成、对象存放、对象取得三个职责。换个方式说,大多的IoC Framework都封装了Service Locator的职责。部分Service Locator也封装了IoC Framework的职责。虽然说结果看起来是一样,但两者设计的出发点是有差异的。

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


  • 相关阅读:
    Unity The Method Signature Matching Rule
    Unity The Property Matching Rule
    Unity The Type Matching Rule
    Unity The Custom Attribute Matching Rule
    Unity The Member Name Matching Rule
    Unity No Policies
    Unity The Return Type Matching Rule
    Unity The Parameter Type Matching Rule
    Unity The Namespace Matching Rule
    关于TSQL递归查询的(转)
  • 原文地址:https://www.cnblogs.com/clark159/p/2511085.html
Copyright © 2011-2022 走看看