.NET
IOC Design Pattern Unity
▌背景
Unity
Application Block (Unity)在泛型的使用方式。
以下分別介紹在Run-time(程式碼注入)以及Design-time(由設定檔注入)的方式。
|
▌環境
l Windows 7 pro
l IIS Express 7.5
l Visual Studio 2013
update4 (C#)
|
▌實作
▋Create Model as “parameter”
in IOC constructor.
l A class which will
be used as a parameter.
l A enum class which
will be used as a parameter.
▋Interface
▋Class
l RedPainter : No constructor
l BluePainter : Constructor with String parameter
l SilverPainter : Constructor with Enum parameter
l BlackPainter : Constructor with Json parameter (Deserize
to an object later)
|
▋Run-time DI
IPainter<ICar> painter = null;
IUnityContainer container = new UnityContainer();
//注入容器 …
container.RegisterType<IPainter<ICar>, BluePainter<ICar>>(
new InjectionConstructor("金額 10,000"));
//取得容器的组件
painter =
container.Resolve<IPainter<ICar>>();
//使用注入的物件
ICar focus = new Focus();
painter.Paint(focus);
//GC
container.Dispose();
|
執行結果 :
已烤漆為藍色! (金額 10,000)
▋Create Model as “parameter”
in IOC constructor.
l A class which will
be used as a parameter.
l A enum class which
will be used as a parameter.
▋Interface
▋Class
l RedPainter : No constructor
l BluePainter : Constructor with String parameter
l SilverPainter : Constructor with Enum parameter
l BlackPainter : Constructor with Json parameter (Deserize
to an object later)
|
▋Run-time DI
IPainter<ICar> painter = null;
IUnityContainer container = new UnityContainer();
//注入容器 …
container.RegisterType<IPainter<ICar>, BluePainter<ICar>>(
new InjectionConstructor("金額 10,000"));
//取得容器的组件
painter =
container.Resolve<IPainter<ICar>>();
//使用注入的物件
ICar focus = new Focus();
painter.Paint(focus);
//GC
container.Dispose();
|
執行結果 :
已烤漆為藍色! (金額 10,000)
▋Design-time DI
l 主程式
using
Microsoft.Practices.Unity.Configuration; // Must for LoadConfiguration
method!
IPainter<ICar> painter = null;
IUnityContainer container = new UnityContainer();
//從Config注入容器 …
container.LoadConfiguration("UnityCfg_Painter");
//取得IFile容器的组件
painter =
container.Resolve<IPainter<ICar>>();
ICar focus = new Focus();
painter.Paint(focus);
//GC
container.Dispose();
|
l 設定檔 : 注入 RedPainter : No constructor
在設定Config前,必須知道下面三個型別的完整型別名稱:
1.
Generic interface
2.
Generic class (which implement 1.)
3.
Generic Data type
在此範例對應為:
1.
IPainter<>
2.
RedPainter<>
3.
ICar
只要使用以下程式碼即可知道完整型別名稱…
Debug.WriteLine(typeof(IPainter<>).AssemblyQualifiedName);
|
Output :
DI_Generic.Strategy.IPainter`1,
DI_Generic,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
接著便可以開始設定Config,
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration" />
</configSections>
<unity>
<assembly name="DPLib" />
<assembly name="DI_Generic" />
<namespace name="DPLib" />
<namespace name="DI_Generic.Strategy" />
<alias alias="CarInterface" type="DPLib.ICar, DPLib" />
<alias alias="PainterInterface" type="DI_Generic.Strategy.IPainter`1,
DI_Generic" />
<alias alias="PainterClass" type="DI_Generic.Strategy.RedPainter`1,
DI_Generic" />
<container name="UnityCfg_Painter">
<register type="PainterInterface[CarInterface]"
mapTo="PainterClass[CarInterface]">
</register>
</container>
</unity>
</configuration>
|
PS. 注意在Register type時的寫法,必須用”[]”包住Generic Data type:
<register type="PainterInterface[CarInterface]"
mapTo="PainterClass[CarInterface]" />
執行結果:
已烤漆為紅色!
l 設定檔 : 注入 BluePainter : Constructor with String parameter
在<Register>
tag裡加入 <constructor> & <param>,注意名稱必須和實際的參數名稱相同。
<configuration>
<unity>
<alias alias="CarInterface" type="DPLib.ICar, DPLib" />
<alias alias="PainterInterface" type="DI_Generic.Strategy.IPainter`1,
DI_Generic" />
<alias alias="PainterClass" type="DI_Generic.Strategy.BluePainter`1,
DI_Generic" />
<container name="UnityCfg_Painter">
<register type="PainterInterface[CarInterface]"
mapTo="PainterClass[CarInterface]">
<constructor>
<param name="extraMsg" value="客戶下午兩點取車"/>
</constructor>
</register>
</container>
</unity>
</configuration>
|
執行結果:
已烤漆為藍色! (客戶下午兩點取車)
l 設定檔 : 注入 SilverPainter
: Constructor with
Enum parameter
參數為列舉型別時,必須手動指定參數的型別,而value的設定方式:
Ex1. value="Wax"
=> Service.Wax
Ex2. value="Wash"
=> Service.Wash
Ex3. value="Clean"
=> Service.Clean
<configuration>
<unity>
<alias alias="CarInterface" type="DPLib.ICar, DPLib" />
<alias alias="PainterInterface" type="DI_Generic.Strategy.IPainter`1,
DI_Generic" />
<alias alias="PainterClass" type="DI_Generic.Strategy.SilverPainter`1,
DI_Generic" />
<container name="UnityCfg_Painter">
<register type="PainterInterface[CarInterface]"
mapTo="PainterClass[CarInterface]">
<constructor>
<param name="service" value="Wax" type="DI_Generic.Service, DI_Generic"/>
</constructor>
</register>
</container>
</unity>
</configuration>
|
執行結果:
已烤漆為銀色! (額外服務:打蠟)
l 設定檔 : 注入 BlackPainter
:
Constructor with Json parameter (Deserize to an object later)
如果注入的class的建構參數為一物件,折衷的方式是帶入JSON,再deserialize成物件。
但是JSON中的雙引號在放進Config時,必須改成HTML字元:"
<configuration>
<unity>
<alias alias="CarInterface" type="DPLib.ICar, DPLib" />
<alias alias="PainterInterface" type="DI_Generic.Strategy.IPainter`1,
DI_Generic" />
<alias alias="PainterClass" type="DI_Generic.Strategy.BlackPainter`1,
DI_Generic" />
<container name="UnityCfg_Painter">
<register type="PainterInterface[CarInterface]"
mapTo="PainterClass[CarInterface]">
<constructor>
<param name="jsonStr" value="{"Name": "JB","Sex": "男","PhoneNumber": "0933123XXX"}" />
</constructor>
</register>
</container>
</unity>
</configuration>
|
執行結果:
已烤漆為黑色! (JB,男,0933123XXX)
▌Conclusion
在寫IOC程式碼時,一開始會花比較多時間,但是完成後,對於程式的彈性和可擴展性都加了不少分。
|
▌Reference
|