你真的了解Ioc与AOP 吗?(2)
三、基于配置文件和Reflection的工廠模式
為了消除MainApp對(duì)其它組件的依賴性,我們引入工廠模式,并且根據(jù)配置文件指定的裝配規(guī)程,利用.net提供的反射技術(shù)完成對(duì)象的組裝工作。本部分代碼僅僅提供一種功能演示,如果實(shí)際應(yīng)用仍需進(jìn)一步完善(建議使用一些成型的Ioc框架,例如Spring.net或Castle等)。經(jīng)過改造后的系統(tǒng),組件間依賴關(guān)系如下圖:
可以看出這次實(shí)現(xiàn)了真正的“針對(duì)接口編程”。所有的組件只依賴于接口。MainApp所需的對(duì)象是由工廠根據(jù)配置文件動(dòng)態(tài)創(chuàng)建并組裝起來的。當(dāng)系統(tǒng)需求發(fā)生變化時(shí),只需要修改一下配置文件就可以了。而且MainApp、SayHello和HelloGenerator之間不存在任何的依賴關(guān)系,實(shí)現(xiàn)了松耦合。
這是如何實(shí)現(xiàn)的呢?我們首先要能夠解析配置文件中的信息,然后建立包含相關(guān)信息的對(duì)象。最后根據(jù)這些信息利用反射機(jī)制完成對(duì)象的創(chuàng)建。首先我們看一下配置文件所包含的內(nèi)容:
<?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>從中我們可以看出,我們實(shí)現(xiàn)了一個(gè)IocInCSharp.ConfigHandler類,用來處理配置文件中 IocInCSharp\objects結(jié)點(diǎn)中的內(nèi)容。ConfigHandler類將根據(jù)該結(jié)點(diǎn)下的內(nèi)容處理并創(chuàng)建一ConfigInfo對(duì)象(關(guān)于 ConfigInfo、ObjectInfo以及PropertyInfo的代碼可自行查看源代碼,這里就不再贅述)。ConfigHandler類的代碼實(shí)現(xiàn)如下:
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的解析,我們最終得到一個(gè)ConfigInfo實(shí)例,Factory就是根據(jù)這個(gè)實(shí)例中所包含的配置信息,利用反射技術(shù)對(duì)所需對(duì)象生成并組裝的。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;}} }在上面這段代碼中,重點(diǎn)注意三條命令的使用方法:
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()用于將外部文件裝載進(jìn)來;assembly.CreateInstance()根據(jù)裝載進(jìn)來的程序集創(chuàng)建一指定類型的對(duì)象;t.InvokeMember(prop.propertyName, ........BindingFlags.SetProperty, null, o, new Object[] {p})利用反射機(jī)制對(duì)創(chuàng)建出來的對(duì)象設(shè)置屬性值。
我們的Factory就是利用這種方式根據(jù)配置文件動(dòng)態(tài)加載程序集,動(dòng)態(tài)創(chuàng)建對(duì)象并設(shè)置屬性的。有了這個(gè)Factory,MainApp中的內(nèi)容就很簡(jiǎn)單了:
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!");}} }現(xiàn)在,MainApp只依賴于接口,不再依賴于其它組件,實(shí)現(xiàn)了松耦合。在本例子中,大家可以嘗試將配置文件中的IocInCSharp.CnHelloGenerator更改為IocInCSharp.EnHelloGenerator,看看是否輸出內(nèi)容由中文變?yōu)榱擞⑽摹_@便是“注入”的效果。
從上面這個(gè)例子我們可以看出,通過自定義配置文件和.net中的Reflection技術(shù),我們自己就可以開發(fā)Ioc應(yīng)用,根據(jù)配置文件的信息自行組裝相應(yīng)的對(duì)象。但是Reflection編程的技術(shù)門檻還是比較高的,并且在實(shí)際應(yīng)用中配置文件的格式、Handler的設(shè)計(jì)都不是象上面代碼那樣的簡(jiǎn)單。不過幸好我們現(xiàn)在有很多的Ioc容器可供選擇,它們都提供了完整的依賴注入方式,并且比自己寫代碼更加成熟、更加穩(wěn)定。使用這些框架可以讓程序員在三兩行代碼里完成“注入”工作。在我們下一個(gè)案例中,我們將使用Spring.net實(shí)現(xiàn)依賴注入。我們會(huì)發(fā)現(xiàn)僅僅添加幾行代碼并更改一下配置文件就可輕松實(shí)現(xiàn)依賴注入。(待續(xù))
轉(zhuǎn)載于:https://www.cnblogs.com/kevin-wang/archive/2010/04/29/1723459.html
總結(jié)
以上是生活随笔為你收集整理的你真的了解Ioc与AOP 吗?(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6499元不赚钱交个朋友 红魔7S Pr
- 下一篇: 砂.随笔.二十五.如果你是氧气