Service Locator 模式

摘要:
该解决方案创建一个ServiceLocator,其中包含每个服务的引用,并封装了查找服务的逻辑。ServiceLocator模式没有描述如何实例化服务,而是描述了注册和定位服务的方法。实现细节通常ServiceLocator类提供IServiceLocator接口的实现单例,并负责管理此实例的创建和访问。注意:在使用ServiceLocator模式之前,请考虑以下几点:程序中有许多元素需要管理。此模式解决了与ServiceLocator模式相同的问题,但使用了不同的方法。
Service Locator 模式

什么是Service Locator 模式?

服务定位模式(Service Locator Pattern)是一种软件开发中的设计模式,通过应用强大的抽象层,可对涉及尝试获取一个服务的过程进行封装。该模式使用一个称为"Service Locator"的中心注册表来处理请求并返回处理特定任务所需的必要信息。

场景描述

某类ClassA依赖于服务ServiceA和服务ServiceB,服务的具体类型需在编译时指定。

Service Locator 模式第1张

这种条件下有以下缺点:

  • 尝试替换或更新依赖项,必须更改类的源代码并且重新编译。
  • 依赖项的具体实现必须在编译时可用。
  • 测试该类非常困难,因为类对依赖项有直接的引用,则依赖项不能使用Stub或Mock对象替换。
  • 该类包含用于创建、定位和管理依赖项的重复代码。

设计目标

使用 Service Locator Pattern 来达成以下目标:

  • 把类与依赖项解耦,从而使这些依赖项可被替换或者更新。
  • 类在编译时并不知道依赖项的具体实现。
  • 类的隔离性和可测试性非常好。
  • 类无需负责依赖项的创建、定位和管理逻辑。
  • 通过将应用程序分解为松耦合的模块,达成模块间的无依赖开发、测试、版本控制和部署。

解决方案

创建一个 Service Locator,其包含各服务的引用,并且封装了定位服务的逻辑。在类中使用 Service Locator 来获取所需服务的实例。

Service Locator 模式第2张

Service Locator 模式并不描述如何实例化服务,其描述了一种注册和定位服务的方式。通常情况下,Service Locator 模式与工厂模式(Factory Pattern)和依赖注入模式(Dependency Injection Pattern)等结合使用。

服务定位器应该能够在不知道抽象类的具体类型的情况下定位到服务。例如,它可能会使用字符串或服务接口类型来影射服务,这允许在无需修改类的条件下替换依赖项的具体实现。

实现细节

通常 ServiceLocator 类提供 IServiceLocator 接口的实现单例,并负责管理该实例的创建和访问。ServiceLocator 类提供 IServiceLocator 接口的默认实现,例如 ActivatingServiceLocator 类,可以同时创建和定位服务。

注意事项

在使用 Service Locator 模式之前,请考虑以下几点:

  • 有很多程序中的元素需要管理。
  • 在使用之前必须编写额外的代码将服务的引用添加到服务定位器。
  • 类将对服务定位器有依赖关系。
  • 源代码变的更加复杂和难以理解。
  • 可以使用配置数据来定义运行时的关系。
  • 必须提供服务的实现。因为服务定位器模式将服务消费者与服务提供者解耦,它可能需要提供额外的逻辑。这种逻辑将保证在服务消费者尝试定位服务之前,服务提供者已被安装和注册。

相关模式

  • 依赖注入(Dependency Injection)。这种模式解决了与 Service Locator 模式相同的问题,但它使用不同的方法。
  • 控制反转(Inversion of Control)。Service Locator 模式是这种模式的特殊版本。它将应用程序的传统控制流程反转。它用被调用对象来代替控制过程的调用方。

参考信息

代码示例

Service Locator 的简单实现,使用静态类实现,未使用Singleton设计,仅作Mapping影射。

复制代码
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;

namespace Infrastructure
{
  /// <summary>
  /// 服务定位器
  /// </summary>
  public static class ServiceLocator
  {
    #region Fields

    private static readonly Dictionary<Type, Type> _mapping = new Dictionary<Type, Type>();
    private static readonly Dictionary<Type, object> _resources = new Dictionary<Type, object>();
    private static object _operationLock = new object();

    #endregion

    #region Add

    /// <summary>
    /// 添加注册资源
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    /// <param name="instance">资源实例</param>
    public static void Add<TClass>(object instance)
        where TClass : class
    {
      Add(typeof(TClass), instance);
    }

    /// <summary>
    /// 添加注册资源
    /// </summary>
    /// <param name="typeOfInstance">资源类型</param>
    /// <param name="instance">资源实例</param>
    public static void Add(Type typeOfInstance, object instance)
    {
      if (typeOfInstance == null)
        throw new ArgumentNullException("typeOfInstance");
      if (instance == null)
        throw new ArgumentNullException("instance");

      if (!(typeOfInstance.IsInstanceOfType(instance)))
      {
        throw new InvalidCastException(
            string.Format(CultureInfo.InvariantCulture,
            "Resource does not implement supplied interface: {0}", typeOfInstance.FullName));
      }

      lock (_operationLock)
      {
        if (_resources.ContainsKey(typeOfInstance))
        {
          throw new ArgumentException(
              string.Format(CultureInfo.InvariantCulture, "Resource is already existing : {0}", typeOfInstance.FullName));
        }
        _resources[typeOfInstance] = instance;
      }
    }

    #endregion

    #region Get

    /// <summary>
    /// 查找指定类型的资源实例
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    /// <returns>资源实例</returns>
    public static TClass Get<TClass>()
        where TClass : class
    {
      return Get(typeof(TClass)) as TClass;
    }

    /// <summary>
    /// 查找指定类型的资源实例
    /// </summary>
    /// <param name="typeOfInstance">The type of instance.</param>
    /// <returns>资源实例</returns>
    public static object Get(Type typeOfInstance)
    {
      if (typeOfInstance == null)
        throw new ArgumentNullException("typeOfInstance");

      object resource;

      lock (_operationLock)
      {
        if (!_resources.TryGetValue(typeOfInstance, out resource))
        {
          throw new ResourceNotFoundException(typeOfInstance.FullName);
        }
      }

      if (resource == null)
      {
        throw new ResourceNotInstantiatedException(typeOfInstance.FullName);
      }

      return resource;
    }

    /// <summary>
    /// 尝试查找指定类型的资源实例
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    /// <param name="resource">资源实例</param>
    /// <returns>是否存在指定资源类型的资源实例</returns>
    public static bool TryGet<TClass>(out TClass resource)
        where TClass : class
    {
      bool isFound = false;

      resource = null;
      object target;

      lock (_operationLock)
      {
        if (_resources.TryGetValue(typeof(TClass), out target))
        {
          resource = target as TClass;
          isFound = true;
        }
      }

      return isFound;
    }

    #endregion

    #region Register

    /// <summary>
    /// 注册类型
    /// </summary>
    /// <typeparam name="TClass">实体类型,类型限制为有公共无参构造函数</typeparam>
    public static void RegisterType<TClass>()
      where TClass : class, new()
    {
      lock (_operationLock)
      {
        _mapping[typeof(TClass)] = typeof(TClass);
      }
    }

    /// <summary>
    /// 注册类型
    /// </summary>
    /// <typeparam name="TFrom">资源类型</typeparam>
    /// <typeparam name="TTo">实体类型,类型限制为有公共无参构造函数</typeparam>
    public static void RegisterType<TFrom, TTo>()
      where TFrom : class
      where TTo : TFrom, new()
    {
      lock (_operationLock)
      {
        _mapping[typeof(TFrom)] = typeof(TTo);
        _mapping[typeof(TTo)] = typeof(TTo);
      }
    }

    /// <summary>
    /// 是否已注册此类型
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    /// <returns>是否已注册此类型</returns>
    public static bool IsRegistered<TClass>()
    {
      lock (_operationLock)
      {
        return _mapping.ContainsKey(typeof(TClass));
      }
    }

    #endregion

    #region Resolve

    /// <summary>
    /// 获取类型实例
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    /// <returns>类型实例</returns>
    public static TClass Resolve<TClass>()
      where TClass : class
    {
      TClass resource = default(TClass);

      bool existing = TryGet<TClass>(out resource);
      if (!existing)
      {
        ConstructorInfo constructor = null;

        lock (_operationLock)
        {
          if (!_mapping.ContainsKey(typeof(TClass)))
          {
            throw new ResourceNotResolvedException(
              string.Format(CultureInfo.InvariantCulture, "Cannot find the target type : {0}", typeof(TClass).FullName));
          }

          Type concrete = _mapping[typeof(TClass)];
          constructor = concrete.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null);
          if (constructor == null)
          {
            throw new ResourceNotResolvedException(
              string.Format(CultureInfo.InvariantCulture, "Public constructor is missing for type : {0}", typeof(TClass).FullName));
          }
        }

        Add<TClass>((TClass)constructor.Invoke(null));
      }

      return Get<TClass>();
    }

    #endregion

    #region Remove

    /// <summary>
    /// 移除指定类型的资源实例
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    public static void Remove<TClass>()
    {
      Teardown(typeof(TClass));
    }

    /// <summary>
    /// 移除指定类型的资源实例
    /// </summary>
    /// <param name="typeOfInstance">资源类型</param>
    public static void Remove(Type typeOfInstance)
    {
      if (typeOfInstance == null)
        throw new ArgumentNullException("typeOfInstance");

      lock (_operationLock)
      {
        _resources.Remove(typeOfInstance);
      }
    }

    #endregion

    #region Teardown

    /// <summary>
    /// 拆除指定类型的资源实例及注册映射类型
    /// </summary>
    /// <typeparam name="TClass">资源类型</typeparam>
    public static void Teardown<TClass>()
    {
      Teardown(typeof(TClass));
    }

    /// <summary>
    /// 拆除指定类型的资源实例及注册映射类型
    /// </summary>
    /// <param name="typeOfInstance">资源类型</param>
    public static void Teardown(Type typeOfInstance)
    {
      if (typeOfInstance == null)
        throw new ArgumentNullException("typeOfInstance");

      lock (_operationLock)
      {
        _resources.Remove(typeOfInstance);
        _mapping.Remove(typeOfInstance);
      }
    }

    #endregion

    #region Clear

    /// <summary>
    /// 移除所有资源
    /// </summary>
    public static void Clear()
    {
      lock (_operationLock)
      {
        _resources.Clear();
        _mapping.Clear();
      }
    }

    #endregion
  }
}
复制代码

Service Locator 测试代码

复制代码
using System;
using Infrastructure;

namespace ServiceLocatorTest
{
  class Program
  {
    interface IServiceA
    {
      string GetData();
    }

    class ServiceA : IServiceA
    {
      public string GetData()
      {
        return "This data is from ServiceA";
      }
    }

    static void Main(string[] args)
    {
      ServiceLocator.RegisterType<IServiceA, ServiceA>();
      IServiceA serviceA = ServiceLocator.Resolve<IServiceA>();
      string data = serviceA.GetData();
      Console.WriteLine(data);
      Console.ReadKey();
    }
  }
}
复制代码

Service Locator 模式第7张

 
 

免责声明:文章转载自《Service Locator 模式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇shell学习(16)- 压缩和解压缩命令tar和zipAndroid视图控件架构分析之View、ViewGroup下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#枚举(一)使用总结以及扩展类分享

0.介绍 枚举是一组命名常量,其基础类型为任意整型。 如果没有显式声明基础类型, 则为Int32 在实际开发过程中,枚举的使用可以让代码更加清晰且优雅。 最近在对枚举的使用进行了一些总结与整理,也发现了一些很有意思的知识盲区。 接下来先简单为大家介绍枚举在开发过程中的常用内容以及扩展类的分享。如果喜欢直接看代码的可以查看最后的样例源码。 1. 参考资料 官...

Sqlite-Sqlite3中的数据类型

大多数的数据库引擎(到现在据我们所知的除了sqlite的每个sql数据库引擎)都使用静态的、刚性的类型,使用静态类型,数据的类型就由它的容器决定,这个容器是这个指被存放的特定列。 Sqlite使用一个更一般的动态类型系统,sqlite中,值的数据类型跟值本身相关,而不是与它的容器相关。Sqlite的动态类型系统和其他数据库的更为一般的静态类型系统相兼容,但...

C# 序列化与反序列化之DataContract与xml对子类进行序列化的解决方案

C# 序列化与反序列化之DataContract与xml对子类进行序列化的解决方案 1、DataContract继承对子类进行序列化的解决方案 第一种是在 [DataContract, KnownType(typeof(继承的子类))]添加 KnownType(typeof(继承的子类))即可,第二种是在序列化的时候,添加类型 DataContractSe...

c语言中typeof关键字

为什么因为一个关键字而专门写一篇随笔呢?因为这个关键字在Linux里面地位非同一般!这个关键字typeof在linux内核里面使用非常广泛! 下面这两个等效声明,用于声明int类弄的变量atypeof(int) a;typeof('b') a; //相当于获取'b'的类型,定义一个变量a下面用于声明指针和数组typeof(int*) p1,p2;typeo...

[译]AngularJS Services 获取后端数据

原文:ANGULARJS SERVICES – FETCHING SERVER DATA $http是AngularJS内置的服务,能帮助我们完成从服务端获数据。简单的用法就是在你需要数据的时候,发起$http请求,使用返回的数据。这个样做是能工作,但是当你的应用越来越复杂的时候,你会发现你在不断的重复的写这个http请求的代码。为了避免这种事情的发生,我...

C#中的typeof()和GetType()的区别

说明:这里只列举了一部分,还有待继续添加: 1、typeof(x)中的x,必须是具体的类名、类型名称等,不可以是变量名称。 2、GetType()方法继承于Object(C#中所有类的基类都是object类。基类是相对于派生类而言的,比方说:如果B类继承自A类,则A就是B的基类。), 所以C#中任何对象都具有GetType()方法,它的作用和typeof(...