Unity 3D Framework Designing(8)——使用ServiceLocator實現對象的註入

来源:http://www.cnblogs.com/OceanEyes/archive/2017/03/31/using_service_locator.html
-Advertisement-
Play Games

對象的 『註入』 是企業級軟體開發經常聽到的術語。如果你是一個 Java 程式員,一定對註入有著深刻的映像。不管是SSH框架還是SSM框架,Spring 全家桶永遠是繞不過去的彎。通過依賴註入,可以有效的解耦應用程式。在uMVVM框架中,我提供了另外一種對象註入的方式,稱為Service Locat ...


對象的 『註入』 是企業級軟體開發經常聽到的術語。如果你是一個 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方法來實現對象的註入。

<!-- 創建對象:Bar-->
<bean id="barId" class="com.xxx.Bar" >
    <property name="service" ref="someServiceId"></property>
</bean>

<!-- 創建SomeService實例 -->
<bean id="someServiceId" class="com.xxx.SomeService"></bean>

可以看到Spring將依賴關係配置到XML中,在運行時,從IoC容器工廠獲取 『Bean(即:實例)』 並將依賴關係註入。

難道我們需要在Unity3D 中定義XML來配置嗎?這會不會太麻煩了?

使用ServiceLocator實現對象的註入

其實對象的 『註入』 有很多實現方式,依賴註入 『DI』 只是其中一種,大名鼎鼎的Spring框架就是非常優秀的依賴註入框架,而uMVVM中實現的註入式通過ServiceLocator實現。

什麼是ServiceLocator?

簡單說ServiceLocator內部以字典的形式維護了對象的依賴關係,外部通過Key的形式獲取到對應的Value,從而達到解耦。

要實現對象的 『註入』 ,還缺一個非常重要的對象,就是IoC容器工廠,所有需要被註入的對象都是由容器工廠創建。那我們哪裡去找工廠呢?還記得上篇文章的內容了嗎?我們已經預先定義了3種不同創建對象的工廠,他們分別為 Singleton Factory,Transient Factory以及 Pool Factory,這些就是我們需要的IoC工廠。

既然 ServiceLocator內部以字典的形式維護了依賴關係,那麼首先需要創建一個字典:

private static readonly Dictionary<Type, Func<object>> Container = new Dictionary<Type, Func<object>>();

註意到字典的Value了嗎,這是一個 Fun ,本質上是一段匿名函數,只有當真正需要的時候,執行這段匿名函數,返回對象。這是一個非常好的設計,也是懶載入的核心。Swift 和 C# 4.0 的Lazy 核心和代碼就是匿名函數。

我們再對Service Locator進行增強,既然要通過字典來維護依賴關係,那我們必須往字典里註冊它們,結合我們的工廠,通過ServiceLocator獲取的對象可以是單例Singleton對象或者臨時Transient對象:

/// <summary>
/// 對每一次請求,只返回唯一的實例
/// </summary>
/// <typeparam name="TInterface"></typeparam>
/// <typeparam name="TInstance"></typeparam>
public static void RegisterSingleton<TInterface, TInstance>() where TInstance : class, new()
{
    Container.Add(typeof(TInterface), Lazy<TInstance>(FactoryType.Singleton));
}
/// <summary>
/// 對每一次請求,只返回唯一的實例
/// </summary>
/// <typeparam name="TInstance"></typeparam>
public static void RegisterSingleton<TInstance>() where TInstance : class, new()
{
    Container.Add(typeof(TInstance), Lazy<TInstance>(FactoryType.Singleton));
}
/// <summary>
/// 對每一次請求,返回不同的實例
/// </summary>
/// <typeparam name="TInterface"></typeparam>
/// <typeparam name="TInstance"></typeparam>
public static void RegisterTransient<TInterface, TInstance>() where TInstance : class, new()
{
    Container.Add(typeof(TInterface),Lazy<TInstance>(FactoryType.Transient));
}
/// <summary>
/// 對每一次請求,返回不同的實例
/// </summary>
/// <typeparam name="TInstance"></typeparam>
public static void RegisterTransient<TInstance>() where TInstance : class, new()
{
    Container.Add(typeof(TInstance),Lazy<TInstance>(FactoryType.Transient));
}

private static Func<object> Lazy<TInstance>(FactoryType factoryType) where TInstance : class, new()
{
    return () =>
    {
        switch (factoryType)
        {
            case FactoryType.Singleton:
                return _singletonObjectFactory.AcquireObject<TInstance>();
            default:
                return _transientObjectFactory.AcquireObject<TInstance>();
        }
        
    };
}

可以看到,其實本質上真的很簡單,就是一個 Key:Value 形式的字典,最後提供一個Resolve方法,可以通過Key來獲取對應的對象:

/// <summary>
/// 從容器中獲取一個實例
/// </summary>
/// <returns></returns>
private static object Resolve(Type type)
{
    if (!Container.ContainsKey(type))
    {
        return null;
    }
    return Container[type]();
 }

使用起來也非常方便,在一個全局初始化文件中去定義這些依賴關係:

 ServiceLocator.RegisterSingleton<IUnitRepository,UnitRepository>();

然後在你的任何業務代碼中以Resolve的形式獲取對象:

 ServiceLocator.Resolve<IUnitRepository>();

小結

使用構造函數或者setter方法依賴註入也好,還是使用ServiceLocator也罷,它們本質上都是去解耦。對象的註入一般需要結合IoC容器,我們已經定義了3種不同的IoC工廠容器。詳細可以翻閱前一篇文章:『Unity 3D Framework Designing(7)——IoC工廠理念先行』。這兩篇文章對於初學者來說是有難度的,因為很多概念都是Web開發經常遇到的,如果需要額外的資料,建議翻閱 《設計模式》 相關書籍。

源代碼托管在Github上,點擊此瞭解


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 結構 用到的包 web.xml <url-pattern>/</url-pattern>中可以換成其他的尾碼*.do ,*. sb …… spring-mvc.xml helloworld.jsp index.jsp 如果上面的web.xml中 <url-pattern>/</url-pattern ...
  • 今天在群里被@了,讓一起分析RpcException的原因。確實一是我手頭事情確實比較多,二是我對不是自己做的東西有種天然的排斥性,不情願看。這方面我需要高強度的修煉。確實是我們部門缺人手,問題緊急,不然兩位男神哥哥也不會這麼麻煩我[偷笑][偷笑][偷笑]。我們組長人真是超級nice,自己那麼忙了, ...
  • 談到 『Repository』 倉儲模式,第一映像就是封裝了對數據的訪問和持久化。Repository 模式的理念核心是定義了一個規範,即介面『Interface』,在這個規範裡面定義了訪問以及持久化數據的行為。開發者只要對介面進行特定的實現就可以滿足對不同存儲介質的訪問,比如存儲在Database ...
  • MyBatis的框架架構 看到Mybatis的框架圖,可以清晰的看到Mybatis的整體核心對象,我更喜歡用自己的圖來表達Mybatis的整個的執行流程。如下圖所示: 原理詳解: MyBatis應用程式根據XML配置文件創建SqlSessionFactory,SqlSessionFactory在根據 ...
  • Spring工作流程如下: 1.springmvc請所有的請求都提交給DispatcherServlet,它會委托應用系統的其他模塊負責負責對請求進行真正的處理工作。 2.DispatcherServlet查詢一個或多個HandlerMapping,找到處理請求的Controller. 3.Disp ...
  • 技術是死的,功能是活的。如何實現一個功能有很多種方式,如何快速靈活高效的實現這些功能就是一門藝術了。這其中可能會組合式的用到設計模式,這就是架構。當你會使用設計模式的時候我相信你會愛上它!一、創建型模式 1、工廠方法模式:使用繼承,動態實例化不同的對象執行相同的方法。 2、抽象工廠模式: 3、單例模 ...
  • 背景: 訂單需要一個不重覆且加密的的訂單號,而且訂單號不能太長!加密說白了就是不想讓任何人從訂單號中看出來今天產生了多少個訂單。訂單號要不重覆且不太長,那就只能是日期+流水號。但是,流水號顯然不能符合加密的需求。所以,流水號就需要加密了。 最初的想法: 初始化一個順序序列的map,然後隨機取出一個數 ...
  • 上面的是springMVC的工作原理圖: 1、客戶端發出一個http請求給web伺服器,web伺服器對http請求進行解析,如果匹配DispatcherServlet的請求映射路徑(在web.xml中指定),web容器將請求轉交給DispatcherServlet. 2、DipatcherServl ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...