你真的了解Ioc与AOP 吗?(2)
三、基于配置文件和Reflection的工廠模式
為了消除MainApp對其它組件的依賴性,我們引入工廠模式,并且根據配置文件指定的裝配規程,利用.net提供的反射技術完成對象的組裝工作。本部分代碼僅僅提供一種功能演示,如果實際應用仍需進一步完善(建議使用一些成型的Ioc框架,例如Spring.net或Castle等)。經過改造后的系統,組件間依賴關系如下圖:
可以看出這次實現了真正的“針對接口編程”。所有的組件只依賴于接口。MainApp所需的對象是由工廠根據配置文件動態創建并組裝起來的。當系統需求發生變化時,只需要修改一下配置文件就可以了。而且MainApp、SayHello和HelloGenerator之間不存在任何的依賴關系,實現了松耦合。
這是如何實現的呢?我們首先要能夠解析配置文件中的信息,然后建立包含相關信息的對象。最后根據這些信息利用反射機制完成對象的創建。首先我們看一下配置文件所包含的內容:
<?xml version="1.0" encoding="utf-8" ?> <configuration><configSections><sectionGroup name="IocInCSharp"><section name="objects" type="IocInCSharp.ConfigHandler, MainApp" /></sectionGroup></configSections><IocInCSharp><objects><object name="SayHello" assembly="SayHello.dll" typeName="IocInCSharp.SayHello"><property name="HelloGenerator" assembly="HelloGenerator.dll" typeName="IocInCSharp.CnHelloGenerator"></property></object></objects></IocInCSharp> </configuration>從中我們可以看出,我們實現了一個IocInCSharp.ConfigHandler類,用來處理配置文件中 IocInCSharp\objects結點中的內容。ConfigHandler類將根據該結點下的內容處理并創建一ConfigInfo對象(關于 ConfigInfo、ObjectInfo以及PropertyInfo的代碼可自行查看源代碼,這里就不再贅述)。ConfigHandler類的代碼實現如下:
using System; using System.Configuration; using System.Xml; namespace IocInCSharp {public class ConfigHandler:IConfigurationSectionHandler{public object Create(object parent, object configContext, System.Xml.XmlNode section){ObjectInfo info;PropertyInfo propInfo;ConfigInfo cfgInfo = new ConfigInfo();foreach(XmlNode node in section.ChildNodes){info = new ObjectInfo();info.name = node.Attributes["name"].Value;info.assemblyName = node.Attributes["assembly"].Value;info.typeName = node.Attributes["typeName"].Value;foreach(XmlNode prop in node){propInfo = new PropertyInfo();propInfo.propertyName = prop.Attributes["name"].Value;propInfo.assemblyName = prop.Attributes["assembly"].Value;propInfo.typeName = prop.Attributes["typeName"].Value;info.properties.Add(propInfo);}cfgInfo.Objects.Add(info);}return cfgInfo;}} }通過ConfigHandler的解析,我們最終得到一個ConfigInfo實例,Factory就是根據這個實例中所包含的配置信息,利用反射技術對所需對象生成并組裝的。SayHelloFactory的代碼如下:
using System; using System.IO; using System.Configuration; using System.Reflection; namespace IocInCSharp {public class SayHelloFactory{public static object Create(string name){Assembly assembly;object o = null;object p;string rootPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;ConfigInfo cfgInfo = (ConfigInfo)ConfigurationSettings.GetConfig("IocInCSharp/objects"); ObjectInfo info = cfgInfo.FindByName(name);if(info != null){assembly = Assembly.LoadFile(rootPath + info.assemblyName);o = assembly.CreateInstance(info.typeName);Type t = o.GetType();for(int i=0; i<info.properties.Count; i++){ PropertyInfo prop = (PropertyInfo)info.properties[i];assembly = Assembly.LoadFile(rootPath + prop.assemblyName);p = assembly.CreateInstance(prop.typeName);t.InvokeMember(prop.propertyName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, o, new Object[] {p});}}return o;}} }在上面這段代碼中,重點注意三條命令的使用方法:
assembly = Assembly.LoadFile(rootPath + prop.assemblyName); p = assembly.CreateInstance(prop.typeName); t.InvokeMember(prop.propertyName, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, o, new Object[] {p});Assembly.LoadFile()用于將外部文件裝載進來;assembly.CreateInstance()根據裝載進來的程序集創建一指定類型的對象;t.InvokeMember(prop.propertyName, ........BindingFlags.SetProperty, null, o, new Object[] {p})利用反射機制對創建出來的對象設置屬性值。
我們的Factory就是利用這種方式根據配置文件動態加載程序集,動態創建對象并設置屬性的。有了這個Factory,MainApp中的內容就很簡單了:
using System; namespace IocInCSharp {public class MainApp{public static void Main(){ISayHello sayHello = (ISayHello)SayHelloFactory.Create("SayHello");if(sayHello != null)sayHello.SayHelloTo("zhenyulu");elseConsole.WriteLine("Got an Error!");}} }現在,MainApp只依賴于接口,不再依賴于其它組件,實現了松耦合。在本例子中,大家可以嘗試將配置文件中的IocInCSharp.CnHelloGenerator更改為IocInCSharp.EnHelloGenerator,看看是否輸出內容由中文變為了英文。這便是“注入”的效果。
從上面這個例子我們可以看出,通過自定義配置文件和.net中的Reflection技術,我們自己就可以開發Ioc應用,根據配置文件的信息自行組裝相應的對象。但是Reflection編程的技術門檻還是比較高的,并且在實際應用中配置文件的格式、Handler的設計都不是象上面代碼那樣的簡單。不過幸好我們現在有很多的Ioc容器可供選擇,它們都提供了完整的依賴注入方式,并且比自己寫代碼更加成熟、更加穩定。使用這些框架可以讓程序員在三兩行代碼里完成“注入”工作。在我們下一個案例中,我們將使用Spring.net實現依賴注入。我們會發現僅僅添加幾行代碼并更改一下配置文件就可輕松實現依賴注入。(待續)
轉載于:https://www.cnblogs.com/kevin-wang/archive/2010/04/29/1723459.html
總結
以上是生活随笔為你收集整理的你真的了解Ioc与AOP 吗?(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6499元不赚钱交个朋友 红魔7S Pr
- 下一篇: 砂.随笔.二十五.如果你是氧气