1.概述 ??????? 如果采用传统方式实现了简单工厂、工厂方法和抽象工厂在有些场合下如此处理,代码会变得冗余并且难以维护。 ??????? 假设我们需要创建一种交通工具,可以是汽车、火车或者轮船,结构如图所示。 ????????????????????? 
????????? 我们可以采用简单工厂,通过参数指示创建所需要的对象类型。如果增加子类,例如卡车和轿车等,则必须增加参数的相应的代码。如果子类层次很多,则会使程序变得难以维护如果用简单工厂实现上面的结构,则显然很烦琐。 ???????? 当然我们可以采用工厂方法来实现,即定义一个产生交通工具的接口,然后在子类中实现创建具体的子类。代码如下: 采用接口定义了抽象的工厂方法 ?
 public
?
Interface?CreateVehicle
 ?????Function?CreateAVehicle()?As?Vehicle?`创建一个交通工具
 End?Interface
 `?具体的创建由子类决定

public
?
Class?CreateCar
 ????Implements?CreateCar
 ????Public?Function?CreateAVheicle()?AsVehicle?Implements
 CreateVehicle.CreateAVehicle
 ????????Return?New?Car
 ?????End?Function
 End?Class
??????? 这就是工厂方法。如果我们希望增加一个新的交通工具,不仅需要实现工具接口,还需要实现产生交通工具的工厂方法。下面是船的具体工厂方法:
 ???
Public
?
Class?CreateBoat
 ???????Implements?CreateVehicle
 ???????Public?Function?CreateAVehicle()?As?Vehicle?Implements
 CreateVehicle.CreateAVehicle
 ????????????Return?New?Boat
 ???????End?Function
 ????End?Class
??????? 显然,如果我们需要产生数十种交通工具则需要有数十个具体的工厂类。而这些工厂类的区别仅仅是返回相应的类的实例,所以为维护带来了麻烦。如果需要在接口中增加一个带参数的创建方法则所有的子类都不得需要修改。 在这个场合下,采用抽象工厂与工厂方法没有区别。因为这里并不涉及产品线,抽象工厂并不能解决其中有的问题。当然,如果每种交通工具都要有对应的车站,则要使用抽象工厂,但是将会更复杂。??????
2.采用反射技术简化工厂类 ??????? 有没有可能将需要创建类的类型传递到工厂方法中,由工厂方法根据类型返回相应的实例? ??????? 解决这个问题的关键是需要动态决定需要创建的类,这不是设计模式能解决的问题属于软件平台的功能范畴。.NET可以提供相应的功能,即反射技术。 我们首先查看采用反射技术实现简化的实例:
 Imports
?System.Reflection

Public
?
Class?CreateVehicleByType
 Implements?CreateVehicle

 Private?VeicleType?As?Type

 Public?Sub?New(ByVal?t?As?Type)
 VeicleType?=?t
 End?Sub

 Public?Function?CreateAVehicle()?As?Vehicle?Implements
 CreateVehicle.CreateAVehicle
 ???????????Dim?objConstructor?As?ConstructorInfo?=
 VeicleType.GetConstructor(System.Type.EmptyTypes)
 ???????????Dim?c?As?Vehicle?=?Ctype(objConstructou.Invoke(Nothing),Vehicle)
 ???????????Return?c?
 ???????End?Function
 End?Class
在使用时,只要在创建时带入需要创建的类的类型:
????
 Private
?
Sub?btcreateByType_Click(ByVal?sender?As?System.Object,ByVal?e?As
 System.EventArgs)?Handles?btCreateBytype.Clik
 ????`根据选择创建一个交通工具并执行GO
 ????Dim?v?As?Vehicle?`我们不知道需要创建的具体交通工具
 ????Dim?f?As?CreateVehicle
 ????If?rCar.Checked?Then
 ????????F?=?New?CreateVehicleByType(GetType(car))
 ????End?If
 ????If?rTrain.Checked?Then
 ????????F?=?New?CreateVehicleByType(GetType(Train))
 ????End?If
 ????If?rBoat.Checked?Then
 ????????F?=?New?CreateVehicleByType(GetType(Boat))
 ????End?If
 ????If?rBus.Checked?Then
 ?????????F?=?New?CreateVehicleByType(GetType(Boat))
 ?????End?If
 ?????V?=?f.CreateAVehicle
 ?????`执行GO指令
 ?????lbGO.Text?=?v.Go
 ??End?Sub

???????? 通过采用反射技术,我们将4个类简化为一个类,并且在新增类型时不需要新的创建这样,我们得到了简化的工厂,可以将其称为“反射工厂”。
3.对简单工厂的改进 ???????? 简单工厂通过参数决定创建的类型,这些参数是在编程时预设的。因此在编译后就无法修改,让我们回顾代码: ???? 我们可以将这个工厂改造为反射工厂:
 ????
Public
?
Class?clsCreateDB
 ????????Public?Shared?Function?CreateDB(ByVal?strType?As?string,?ByVal?strConnString?AsString)?As?_?clsAbstractDB
 ????????????Select?Case?strType.ToUpper
 ????????????????Case?“ORACLE”
 ????????????????????Dim?myOracle?As?clsoracleDB
 ????????????????????MyOracle?=?New?clsOracleDB(strConnString)
 ????????????????????Return?myOracle
 ????????????????Case?“SQLSERVER”
 ????????????????????Dim?mysqlserver?As?clsSQLServerDB
 ????????????????????Mysqlserver?=?New?clsSQLServerDB(strConnString)
 ????????????????????Return?mysqlserver
 ????????????????Case?Else
 ????????????????????Dim?myoledb?As?clsOLEDB
 ????????????????????Myoledb?=?New?clsOLEDB(strConnString)
 ????????????????????Return?myoledb
 ?????????????End?Select
 ?????????End?Function
 ?????End?Class

?????? ???????? 这样解决了简单工厂必须依赖每个具体产品的问题,将表态依赖变为动态绑定.当引入新的数据库类型时,不需要修改工厂即可满足需要。?
4.反射与工厂方法 ??????? 如果工厂方法仅仅是为了获得某个产品的实例,那么完全可以使用反射技术来实现工厂方法。这样解决了工厂方法的潜在问题,即当增加产品类时,必须增加相应的子类。 ???????? 然而当工厂方法所存在的类不仅是实例化产品时,采用反射不一定是好办法,因为可能使问题变得复杂。
5.反射与抽象工厂 ???????? 可以采用反射来实现抽象工厂,这时抽象工厂可能变成了使用反射技术的具体工厂,不再有子类存在。创建交通系统的实例可以用如下的代码来写:


'
<summary>
 '
VehicleSystemReflectionFactory?采用反射技术的工厂。
 '
</summary>

Public
?
Class?VehicleSystemReflectionFactory
 ????Dim?vehicleType?As?String
 ????Dim?vehicleStationType?As?String
 ????Public?Sub?New(ByVal?vt?As?String,?ByVal?vst?As?String)
 ????????Me.vehicleType?=?vt
 ????????Me.vehicleStationType?=?vst
 ????End?Sub
 ????Public?Function?GetVehicle()?As?Vehicle
 ????????Return?CType(createbytype(Me.vehicleType),?Vehicle)
 ????End?Function

 ????Public?Function?GetVehicleStation()?As?VehicleStation
 ????????Return?CType(createbytype(Me.vehicleStationType),?VehicleStation)
 ????End?Function
 ????Private?Function?createbytype(ByVal?vt?As?String)?As?Object
 ????????Dim?tt?As?Type
 ????????tt?=?Type.GetType(vt)
 ????????Dim?ci?As?ConstructorInfo
 ????????ci?=?tt.GetConstructor(System.Type.EmptyTypes)
 ????????Dim?null?As?System.DBNull
 ????????Return?ci.Invoke(null)
 ????End?Function

 End?Class

这种情况下,抽象工厂就变为了只有一个类的反射工厂。
6.反射工厂的使用效果 ???????? 使用反射工厂的优点是极大地减少了工厂类的数量、降低了代码的冗余,并且系统更容易扩展,在增加新类型后,不需要修改工厂类。 ???????? 使用反射工厂的代价是工厂与产品之间的依赖关系不明显,由于是动态绑定,因此理论上可以用一个工厂完成很多类型的实例化,从而使得代码 不容易理解。另外增大了测试难度,创建是动态完成的,测试用例的编写和测试执行要比传统的工厂困难。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|