Unity淺析


在分析PRISM項目的時候, 發現里面用到了Unity 這個Component, 主要用於依賴注入的。由於對其不熟悉,索性分析了一下,記載在此,以作備忘。

任何事物的出現,總有它獨特的原因,Unity也是如此。

在Unity產生之前,我們是這么做的

在遠古的時候,當我們需要在一個類A中引用另一個類B的時候,總是將類B的實例放置到類A的構造函數中,以便在初始化類A的時候,得到類B的實例。

    public class A
    {
        B b;
        public A()
        {
            B = new B();
        }
    }

但是,當項目稍微大一點的時候,維護起來就顯得異常吃力,尤其是當有Code Change的時候,如果類B有了一些修改(比如加入了帶參構造等等),那么這種修改和測試將是異常難受的。

所以,為了解決最原始的問題,我們開始在類A的外部獲取類B的實例,以便能夠減輕依賴:

    public class A
    {
        B b;
        public A(B _b)
        {
            This.b = _b;
        }
    }

這樣,只需要在外部實例化B,然后傳入類A即可。這樣做,雖然比原始做法方便了許多,然是在類A內部,依然存在着對類B的依賴。由於類B在系統中是唯一的,所以說當有許多個類似於類B的對象需要進行初始化的時候,這種工作量…誰能夠想象呢?

有了問題,才會思考變化,於是接口開始在這方面體現他的威力了:

    public class A
    {
        IMyObject myObj;
        public A(IMyObject myObj)
        {
            this.myObj = myObj;
        }
    }

將相似的操作抽出來,放入接口中。現在,你就擁有了許多可以操縱的類對象(繼承了IService接口的類)。並且采用接口以后,你可以更加容易的進行開發和測試,並且維護起來也相對簡單。比如,如果你想測試接口中的DataExtracting功能,那么你完全可以寫一個類繼承自這個接口,只實現DataExtracting功能即可,簡單,方便。

在Unity產生之后,我們是這么做的

現在,Unity將這種操作更加的簡單化,我們可以理解為這樣,Unity將繼承了接口的類進行了橫切,然后提供了還原的方法:

進行依賴注入:

        UnityContainer container = new UnityContainer();

        private void button1_Click(object sender, EventArgs e)
        {
            container.RegisterType<IMyObject, MyObjectFirstImplementation>(DependencyRegistrationKeys.FirstImplementation);
            container.RegisterType<IMyObject, MyObjectSecondImplementation>(DependencyRegistrationKeys.SecondImplementation);

            container.RegisterType<IMyObject, MyObjectThirdImplementation>();
            container.RegisterType<IMyObject, MyObjectFirstImplementation>();

        }

 

還原實體類:

       public MyObjectFactory(UnityContainer unityContainer)
        {
            this.unityContainer = unityContainer;
        }

        public UnityContainer unityContainer;

        public IMyObject Create(string objKey)
        {
            return unityContainer.Resolve<IMyObject>(objKey);
        }

最后給出一個例子作為參考,這個例子主要是講解Unity如何進行注冊對象以及還原的:

實例說明

首先,我們需要有一個IMyObject接口,然后有三個類繼承自此對象:

接口:

View Code
namespace UnityDaemon
{
    public interface IMyObject
    {
        string DoSomething();
    }
}

MyObjectFirstImplementation類:

View Code
namespace UnityDaemon
{
    public class MyObjectFirstImplementation:IMyObject
    {
        public string DoSomething()
        {
            return "You call me ? I am the first one,  I am from MyObjectFirstImplementation!! ";
        }
    }
}

MyObjectSecondImplementation類:

View Code
namespace UnityDaemon
{
    public class MyObjectSecondImplementation:IMyObject
    {
        public string DoSomething()
        {
            return "You call me ? I am the second one, I am from MyObjectSecondImplementation!! ";
        }
    }
}

MyObjectThirdImplementation類:

View Code
namespace UnityDaemon
{
    public class MyObjectThirdImplementation:IMyObject
    {
        public string DoSomething()
        {
            return  "I am the third. Do whatever you want to ~~~";
        }
    }
}

當然,這里我們還可以增加更多的類...

然后,我們需要創建一個Factory,用於根據Object名稱來還原對象:

View Code
using Microsoft.Practices.Unity;

namespace UnityDaemon
{
    public class MyObjectFactory
    {
        public MyObjectFactory() { }

        public MyObjectFactory(UnityContainer unityContainer)
        {
            this.unityContainer = unityContainer;
        }

        public UnityContainer unityContainer;

        public IMyObject Create(string objKey)
        {
            return unityContainer.Resolve<IMyObject>(objKey);
        }
    }
}

這樣做完之后,我們就可以來使用了,我利用Winform做的界面,Button1用來注冊類型,Button2用來還原有名稱的對象,Button3用來還原無名稱的對象:

View Code
using System;
using System.Windows.Forms;
using Microsoft.Practices.Unity;

namespace UnityDaemon
{
    public partial class MainFrm : Form
    {
        UnityContainer container;

        public MainFrm()
        {
            InitializeComponent();
            container = new UnityContainer();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            container.RegisterType<IMyObject, MyObjectFirstImplementation>(DependencyRegistrationKeys.FirstImplementation);
            container.RegisterType<IMyObject, MyObjectSecondImplementation>(DependencyRegistrationKeys.SecondImplementation);

            container.RegisterType<IMyObject, MyObjectThirdImplementation>();
            container.RegisterType<IMyObject, MyObjectFirstImplementation>();

        }

        private void button2_Click(object sender, EventArgs e)
        {
            var factory = new MyObjectFactory(container);
            var myObj = factory.Create(DependencyRegistrationKeys.FirstImplementation);
            string str = myObj.DoSomething();
            MessageBox.Show(str);

            var myObj1 = factory.Create(DependencyRegistrationKeys.SecondImplementation);
            string str1 = myObj1.DoSomething();
            MessageBox.Show(str1);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            var myObj1 = container.Resolve<IMyObject>();

            MessageBox.Show(myObj1.DoSomething());
        }
    }
}

這樣,當我們運行起來,先點擊Button1的時候,三個類都被注冊進了容器中。當點擊Button2的時候,顯示出來的結果和預想一樣。當點擊Button3的時候,僅僅顯示了

You call me ? I am the first one,  I am from MyObjectFirstImplementation!!

原因是什么呢? 原因就在於當注冊的時候,沒有提供名稱的話,那么解析的時候,則以最后一次注冊的為准。所以這也是MyObjectThirdImplementation類中的函數沒有被執行的原因。

源碼下載

點擊這里下載

參考連接

http://stackoverflow.com/questions/4612054/wpf-prism-what-is-a-unity-container

http://blogsprajeesh.blogspot.hk/search/label/PRISM

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM