上一篇说了 abstract factory 和简单工厂,下面简单介绍一下反射工厂。
先说一下反射技术吧,看下面2段代码:
// The conventional way to call an object
businessObject bo=new businessObject();
bo.DoWork();
//The .net reflection way to call a object
Assembly assm=Assembly.Load("TestApp");
Type objType=assm.GetType("TestApp.BusinessObject");
object objInstance=Activator.CreateInstance(objType);
objType.InvokeMember("DoWork",BindingFlags.InvokeMethod,null,objInstance,null)
以上是功能完全相同的2段代码,前一段是普通的类的方法的调用,后一段是用反射写成的。注意后一个代码段中所有的类名方法名都是字符串,所以我们可以使用在运行时刻赋值的字符串变量,来代替硬编码的字符串。这样,就避免了应用直接依赖于特定的具体类。将指定具体类推迟到了运行时刻。
顺便也说一下反射的缺点,如果使用了错误的类名或方法名,编译器是无法识别错误的,只有在运行时才能看到错误。另外,IDE环境下的智能感应也无法为你服务了。
OK,继续。
反射中的类或者方法既然都是字符串,那我们是多么方便的使用配置文件储存这些信息。在我们替换工厂或者类时,只需要更改配置文件就可以了。
示意代码如下:(抽象工厂)
客户端:
ProductFactory pf;
pf=ClassFactory.GetFactory("ProducFactoryA");
Product cheapProduct=pf.GetCheapProduct();
Product.RaisePrice()
Class Factory 的GetFactory方法(反射)
{
public static object GetFactory(string factoryName)
{
object factory=null;
xmlNode classFactoryData=ConfigurationSettings.GetFactoryData(factoryName);
string type=classFactoryData.attributes["type"].Value;
Type t=System.Type.GetType(type);
factory=Activator.CreateInstance(t,null);
return factory;
}
}
配置文件
<Class name="ProductFactoryA" type="OneConcreteProductFactory">
OneConcretePRoductFactory 是程序集中继承了ProductFactory 的具体类。
如果那天需要替换为 NewConcreteProductFactory, 只需要创建好NewConcreteProductFactory后,在配置文件改一下就可以了。其他地方的代码一点都不用动。
再介绍反射工厂的另一种用法:前面已经提到过,面向接口编程是优秀的编程方法。在不new一个具体类的情况下使用接口,除了使用类工厂外,我们还可以使用反射的方法,“自动”找到程序集中实现接口的具体类,进而使用它。
Dim testAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly
For Each type In testAssembly.GetTypes()
If Not type Is Nothing AndAlso Not type.IsAbstract AndAlso GetType(AbstractClassBase).IsAssignableFrom(type) Then
Dim test As AbstractClassBase
test = CType(Activator.CreateInstance(type), AbstractClassBase)
currentTest = test
If args.Length > 0 Then
Try
test.HandleCommandLineArguments(args)
Catch ex2 As Exception
System.Console.WriteLine(ex2.ToString())
System.Diagnostics.Trace.WriteLine(ex2.ToString())
'Exit Sub
End Try
End If
test.Execute()
Next
AbstractClassBase 是一个抽象类
test 是我们获得的事先不知道的程序集中的具体类
System.Reflection.Assembly.GetExecutingAssembly 获取当前程序集
Type.IsAssignableFrom (c) 的返回值
true if c and the current Type represent the same type, or if the current Type is in the inheritance hierarchy of c, or if the current Type is an interface that c implements, or if c is a generic type parameter and the current Type represents one of the constraints of c
呵呵,这么简单的英文就不翻译了。
好用吧。