Unity是一個輕量級AOP框架,提供構造注入、攔截注入、屬性注入、方法注入,使用起來很方便
一、簡單實例注入
先看一個應用場景。一個應用程序中我想定義一個窗口,做為用戶UI,窗口有高度和寬度兩種屬性
namespace ConsoleUnityDemo
{
public class MyWindow
{
public int Height { get; set; }
public int Width { get; set; }
}
class Program
{
static void Main(string[] args)
{
MyWindow myWindow = new MyWindow();
myWindow.Height = 80;
myWindow.Width = 100;
Console.WriteLine(string.Format("Width:{0} Height:{1}", myWindow.Width, myWindow.Height));
}
}
}
窗口的高屬性會經常改變,所以要將myWindow實例的屬性移到配置中,通常會在<appsetting/>中通過<add key />來添加配置,這樣的話需要加兩個配置,如
<appSettings> <add key="Height" value="200"/> <add key="Width" value="300"/> </appSettings>
但是如果應用程序中有兩個MyWindow實例呢?再加上<add key=”Heithgt2”/><add key=”Width2”/>嗎?那再多呢?
Unity提供了輕松實例注入的功能,將對象的實例化移到了應用程序的外部。使用Unity要先引用以下類庫,Unit下載:http://http://unity.codeplex.com/
Microsoft.Practices.Unity.dll Microsoft.Practices.Unity.Configuration.dll
修改為以下代碼
namespace ConsoleUnityDemo { public class MyWindow { public int Height { get; set; } public int Width { get; set; } } class Program { static void Main(string[] args) { UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); UnityContainer unityContainer = new UnityContainer(); unitySection.Configure(unityContainer); //獲取容器 MyWindow myWindow = unityContainer.Resolve<MyWindow>("FirstMyWindow"); //取實例 Console.WriteLine(string.Format("Width:{0} Height:{1}", myWindow.Width, myWindow.Height)); } } }
App.config配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="MyWindow" type="ConsoleUnityDemo.MyWindow, ConsoleUnityDemo" /> <container> <register type="MyWindow" name="FirstMyWindow" mapTo ="MyWindow"> <property name="Height" value="80" type="int" /> <property name="Width" value="100" type="int" /> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> </appSettings> </configuration>
configSections中section添加了一個名為Unity容器,<unity/>節點的注冊了MyWindow類,別名為MyWindow,type中填寫類型的完整名稱和類型的命名空間,<container/>節點下<register/>注冊一個新實例,這樣一來MyWindow實例屬性就被移除到程序外部了。實際應用中,通常有多種類型的MyWindow,應該將MyWindow象為接口。
配置文件做如下修改
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="MyWindow" type="ConsoleUnityDemo.MyWindow, ConsoleUnityDemo" /> <alias alias="IWindow" type="ConsoleUnityDemo.IWindow, ConsoleUnityDemo" /> <container> <register type="IWindow" name="FirstMyWindow" mapTo ="MyWindow"> <property name="Height" value="80" type="int" /> <property name="Width" value="100" type="int" /> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> </appSettings> </configuration>
添加alias別名為IWindow的IWindow類型。register注冊為IWindow, mapTo為實際要創建的類,這就如同
IWindow MyFirstWindow = new MyWindow
再看看工場模式,創建window改用模塊方法:
工場模式中需要IWindow泛化,還需要一個在場類,這樣才能和Window解偶,並且需要修改Factory方法才可以創建新的Window。使用Unit容器中<register/>的mapTo屬性就可以輕松實現工場模式了,Unity替代了Factory的工作。再看下抽象工場:
現在需要在一種window中創建一個配套的menu,所以使用了抽象工場,在Client中獲取實現IAbstracgtFactory的工場就可以創建一套window. 抽象工場中會定義多個,如MyWindowFactory,OtherWindowFactory。在Unity中通過修改Cantoner name屬性就可輕松搞寫
namespace ConsoleUnityDemo { public interface IWindow { int Height { get; set; } int Width { get; set; } void Show(); } public interface IMenu { string MenuText { get; set; } string MenuColor { get; set; } } public class MyWindow : IWindow { public int Height { get; set; } public int Width { get; set; } public void Show() { Console.WriteLine("Show MyWindow"); } } public class MyMenu : IMenu { public string MenuText { get; set; } public string MenuColor { get; set; } } class Program { static void Main(string[] args) { UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); UnityContainer unityContainer = new UnityContainer(); unitySection.Configure(unityContainer, "AbstractFactory"); //獲取容器 IWindow myWindow = unityContainer.Resolve<IWindow>("FirstMyWindow"); //取實例 IMenu myMenu = unityContainer.Resolve<IMenu>("FirstMyMenu"); Console.WriteLine(string.Format("Width:{0} Height:{1}", myWindow.Width, myWindow.Height)); } } }
配置文件如下,將container name屬性設置為AbstractFacotry,代碼中用unitySection.Configure(unityContainer, "AbstractFactory"); 獲取工場。如果增加一個工場,則添加一個Container
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <alias alias="MyWindow" type="ConsoleUnityDemo.MyWindow, ConsoleUnityDemo" /> <alias alias="IWindow" type="ConsoleUnityDemo.IWindow, ConsoleUnityDemo" /> <alias alias="IMenu" type="ConsoleUnityDemo.IMenu, ConsoleUnityDemo" /> <alias alias="MyMenu" type="ConsoleUnityDemo.MyMenu, ConsoleUnityDemo" /> <container name="AbstractFactory"> <register type="IWindow" name="FirstMyWindow" mapTo ="MyWindow"> <property name="Height" value="80" type="int" /> <property name="Width" value="100" type="int" /> </register> <register type="IMenu" name="FirstMyMenu" mapTo ="MyMenu"> <property name="MenuText" value="testValue" /> <property name="MenuColor" value="ColorValue" /> </register> </container> </unity>