博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity应用架构设计(8)——使用ServiceLocator实现对象的注入
阅读量:5337 次
发布时间:2019-06-15

本文共 4190 字,大约阅读时间需要 13 分钟。

对象的 『注入』 是企业级软件开发经常听到的术语。如果你是一个 Java 程序员,一定对注入有着深刻的映像。不管是SSH框架还是SSM框架,Spring 全家桶永远是绕不过去的弯。通过依赖注入,可以有效的解耦应用程序。在uMVVM框架中,我提供了另外一种对象注入的方式,称为Service Locator 『服务定位模式』 。与Spring的依赖注入不同的是,Service Locator 内部以字典的形式维护了对象的依赖关系,外部通过Key的形式获取 『Resolve』 到对应的Value,从而达到解耦。

为什么要注入对象

简而言之,为了解耦,达到 不去依赖 具体的对象。

实际上解耦是个非常 『虚』 的概念,只有软件到达一定的复杂度之后才会明白解耦和的好处,对于一个简单如『Hello World』程序而言,你很难理解为什么需要解耦。

假设有个 Foo 类,需要通过调用 SomeService 对象的方法去执行一些任务。很简单的需求,你可能会这样写:

public class Foo{    ISomeService _service;    public Foo()    {        _service = new SomeService();    }    public void DoSomething()    {        _service.PerformTask();        ...    }}

这当然没问题,但有隐患,Foo 紧耦合了 SomeService,当需求变了,你不得不打开 Foo 类,然后找到构造函数,重新调用另外的 Service,改完之后编译,然后部署、测试等等。如果是Web程序,你还得在等到晚上去部署。

既然紧耦合了,那就解耦,你可能会这样写:

public class Foo{    ISomeService _service;    public Foo(ISomeService service)    {        _service = service;    }    public void DoSomething()    {        _service.PerformTask();        ...    }}

这样很不错,Foo 与具体的 Service 解耦了,那怎样去实例化 Foo 呢?比如有一个 Bar 类:

public class Bar{    public void DoSomething()    {        var foo = new Foo(new SomeService());        foo.DoSomething();        ...    }}

遗憾的是,BarSomeService 又耦合了。然后你又改成这样:

public class Bar{    ISomeService _service;    public Bar(ISomeService service)    {        _service = service;    }    public void DoSomething()    {        var foo = new Foo(_service);        foo.DoSomething();        ...    }}

通过构造函数传递参数,BarSomeService 解耦了。但你打算怎样去实例化 Bar 呢?

额...(-。-;)

Spring中的依赖注入

Spring中将上述 Foo、Bar 类对SomeService的依赖关系,通过构造函数或者setter方法来实现对象的注入。

可以看到Spring将依赖关系配置到XML中,在运行时,从IoC容器工厂获取 『Bean(即:实例)』 并将依赖关系注入。

难道我们需要在Unity3D 中定义XML来配置吗?这会不会太麻烦了?

使用ServiceLocator实现对象的注入

其实对象的 『注入』 有很多实现方式,依赖注入 『DI』 只是其中一种,大名鼎鼎的Spring框架就是非常优秀的依赖注入框架,而uMVVM中实现的注入式通过ServiceLocator实现。

什么是ServiceLocator?

简单说ServiceLocator内部以字典的形式维护了对象的依赖关系,外部通过Key的形式获取到对应的Value,从而达到解耦,如下图所示:

o_serviceLocator.png

要实现对象的 『注入』 ,还缺一个非常重要的对象,就是IoC容器工厂,所有需要被注入的对象都是由容器工厂创建。那我们哪里去找工厂呢?还记得上篇文章的内容了吗?我们已经预先定义了3种不同创建对象的工厂,他们分别为 Singleton Factory,Transient Factory以及 Pool Factory,这些就是我们需要的IoC工厂。

既然 ServiceLocator内部以字典的形式维护了依赖关系,那么首先需要创建一个字典:

private static readonly Dictionary
> Container = new Dictionary
>();

注意到字典的Value了吗,这是一个 Fun <object>,本质上是一段匿名函数,只有当真正需要的时候,执行这段匿名函数,返回对象。这是一个非常好的设计,也是懒加载的核心。Swift 和 C# 4.0 的Lazy 核心和代码就是匿名函数。

我们再对Service Locator进行增强,既然要通过字典来维护依赖关系,那我们必须往字典里注册它们,结合我们的工厂,通过ServiceLocator获取的对象可以是单例Singleton对象或者临时Transient对象:

/// /// 对每一次请求,只返回唯一的实例/// /// 
///
public static void RegisterSingleton
() where TInstance : class, new(){ Container.Add(typeof(TInterface), Lazy
(FactoryType.Singleton));}///
/// 对每一次请求,只返回唯一的实例/// ///
public static void RegisterSingleton
() where TInstance : class, new(){ Container.Add(typeof(TInstance), Lazy
(FactoryType.Singleton));}///
/// 对每一次请求,返回不同的实例/// ///
///
public static void RegisterTransient
() where TInstance : class, new(){ Container.Add(typeof(TInterface),Lazy
(FactoryType.Transient));}///
/// 对每一次请求,返回不同的实例/// ///
public static void RegisterTransient
() where TInstance : class, new(){ Container.Add(typeof(TInstance),Lazy
(FactoryType.Transient));}private static Func
Lazy
(FactoryType factoryType) where TInstance : class, new(){ return () => { switch (factoryType) { case FactoryType.Singleton: return _singletonObjectFactory.AcquireObject
(); default: return _transientObjectFactory.AcquireObject
(); } };}

可以看到,其实本质上真的很简单,就是一个 Key:Value 形式的字典,最后提供一个Resolve方法,可以通过Key来获取对应的对象:

/// /// 从容器中获取一个实例/// /// 
private static object Resolve(Type type){ if (!Container.ContainsKey(type)) { return null; } return Container[type](); }

使用起来也非常方便,在一个全局初始化文件中去定义这些依赖关系:

ServiceLocator.RegisterSingleton
();

然后在你的任何业务代码中以Resolve的形式获取对象:

ServiceLocator.Resolve
();

小结

使用构造函数或者setter方法依赖注入也好,还是使用ServiceLocator也罢,它们本质上都是去解耦。对象的注入一般需要结合IoC容器,我们已经定义了3种不同的IoC工厂容器。详细可以翻阅前一篇文章:『』。这两篇文章对于初学者来说是有难度的,因为很多概念都是Web开发经常遇到的,如果需要额外的资料,建议翻阅 《设计模式》 相关书籍。

源代码托管在Github上,

转载于:https://www.cnblogs.com/OceanEyes/p/using_service_locator.html

你可能感兴趣的文章
[Windows Server]安装系统显示“缺少计算机所需的介质驱动程序”解决方案
查看>>
[容斥][dp][快速幂] Jzoj P5862 孤独
查看>>
Lucene 学习之二:数值类型的索引和范围查询分析
查看>>
软件开发工作模型
查看>>
Java基础之字符串匹配大全
查看>>
面向对象
查看>>
lintcode83- Single Number II- midium
查看>>
移动端 响应式、自适应、适配 实现方法分析(和其他基础知识拓展)
查看>>
selenium-窗口切换
查看>>
使用vue的v-model自定义 checkbox组件
查看>>
[工具] Sublime Text 使用指南
查看>>
Hangfire在ASP.NET CORE中的简单实现方法
查看>>
Algorithm——何为算法?
查看>>
Web服务器的原理
查看>>
小强升职计读书笔记
查看>>
常用的107条Javascript
查看>>
#10015 灯泡(无向图连通性+二分)
查看>>
忘记root密码,怎么办
查看>>
linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
查看>>
《黑客与画家》 读书笔记
查看>>