Service Locator 模式

简介:

什么是Service Locator 模式?

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

场景描述

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

这种条件下有以下缺点:

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

设计目标

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

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

解决方案

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

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();
    }
  }
}
复制代码








本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/archive/2013/04/12/service_locator_pattern.html,如需转载请自行联系原作者

目录
相关文章
|
数据可视化 BI
探索ERP系统的移动端应用与移动办公解决方案
探索ERP系统的移动端应用与移动办公解决方案
508 2
|
canal 关系型数据库 MySQL
cancal 同步mysql数据到es中
cancal 同步mysql数据到es中
429 1
|
前端开发 fastjson Java
我的字段被FastJson给干掉了?!
本文记录作者升级到 JDK 11 后遇到的 FastJSON 序列化问题,以及详细的排查过程。
315 12
|
12月前
|
存储 Java API
如何使用 Java 中的 API 更改 PDF 纸张大小
如何使用 Java 中的 API 更改 PDF 纸张大小
223 11
|
Java Spring
如何通过配置文件给 @Scheduled(fixedRate= )传值
【4月更文挑战第18天】如何通过配置文件给 @Scheduled(fixedRate= )传值
1245 3
|
Arthas 测试技术
Arthas下载与启动
Arthas下载与启动
1017 0
|
存储 并行计算 测试技术
NumPy 性能优化:提升 Python 数值计算的速度
【8月更文第30天】Python 是一种广泛使用的编程语言,在科学计算领域尤其受欢迎。然而,由于 Python 的动态类型和解释执行机制,其在处理大规模数值数据时可能会显得相对较慢。为了克服这一限制,NumPy(Numerical Python)库提供了高性能的多维数组对象以及一系列用于操作这些数组的函数。本文将探讨如何利用 NumPy 来提高 Python 中数值运算的效率。
1146 1
|
Java
SpringBoot项目下的对象属性复制工具类
SpringBoot项目下的对象属性复制工具类
284 1
|
搜索推荐 算法 UED
技术文档指南:版本说明、网站文案、FAQ、案例研究与内容优化
Release Notes 通常是软件文档的一部分,是在新产品发布时提供给用户的简短、高级摘要。它们包含有关更新的重要信息,包括新功能、增强功能、错误修复,通常还包括已知问题。每个版本说明与特定软件版本相关联,并帮助用户了解该特定版本中可以期待的哪些更改或改进。有效的版本说明将以用户为中心的方式讨论新功能或增强功能,识别用户需要执行的任何操作,突出已知问题和解决方法,并在必要时包含指向更详细信息的链接。它使用户能够更有效地使用软件并解决潜在问题。
460 0