Dot NET设计模式—反射工厂

1.概述
        如果采用传统方式实现了简单工厂、工厂方法和抽象工厂在有些场合下如此处理,代码会变得冗余并且难以维护。
        假设我们需要创建一种交通工具,可以是汽车、火车或者轮船,结构如图所示。
                      %E4%BA%A4%E9%80%9A%E5%B7%A5%E5%85%B7%E7%9A%84%E7%BB%93%E6%9E%84.jpg
          我们可以采用简单工厂,通过参数指示创建所需要的对象类型。如果增加子类,例如卡车和轿车等,则必须增加参数的相应的代码。如果子类层次很多,则会使程序变得难以维护如果用简单工厂实现上面的结构,则显然很烦琐。
         当然我们可以采用工厂方法来实现,即定义一个产生交通工具的接口,然后在子类中实现创建具体的子类。代码如下:
采用接口定义了抽象的工厂方法
 

ExpandedBlockStart.gif ContractedBlock.gif public   Interface CreateVehicle Interface CreateVehicle
ExpandedSubBlockStart.gifContractedSubBlock.gif     
Function CreateAVehicle()Function CreateAVehicle() As Vehicle `创建一个交通工具
ExpandedBlockEnd.gif
End Interface

None.gif` 具体的创建由子类决定
ExpandedBlockStart.gifContractedBlock.gif
public   Class CreateCar Class CreateCar
InBlock.gif    
Implements CreateCar
ExpandedSubBlockStart.gifContractedSubBlock.gif    
Public Function CreateAVheicle()Function CreateAVheicle() AsVehicle Implements
InBlock.gifCreateVehicle.CreateAVehicle
InBlock.gif        
Return New Car
ExpandedSubBlockEnd.gif     
End Function

ExpandedBlockEnd.gif
End Class


        这就是工厂方法。如果我们希望增加一个新的交通工具,不仅需要实现工具接口,还需要实现产生交通工具的工厂方法。下面是船的具体工厂方法:

ExpandedBlockStart.gif ContractedBlock.gif     Public   Class CreateBoat Class CreateBoat
InBlock.gif       
Implements CreateVehicle
ExpandedSubBlockStart.gifContractedSubBlock.gif       
Public Function CreateAVehicle()Function CreateAVehicle() As Vehicle Implements
InBlock.gifCreateVehicle.CreateAVehicle
InBlock.gif            
Return New Boat
ExpandedSubBlockEnd.gif       
End Function

ExpandedBlockEnd.gif    
End Class


        显然,如果我们需要产生数十种交通工具则需要有数十个具体的工厂类。而这些工厂类的区别仅仅是返回相应的类的实例,所以为维护带来了麻烦。如果需要在接口中增加一个带参数的创建方法则所有的子类都不得需要修改。
在这个场合下,采用抽象工厂与工厂方法没有区别。因为这里并不涉及产品线,抽象工厂并不能解决其中有的问题。当然,如果每种交通工具都要有对应的车站,则要使用抽象工厂,但是将会更复杂。      

2.采用反射技术简化工厂类
        有没有可能将需要创建类的类型传递到工厂方法中,由工厂方法根据类型返回相应的实例?
        解决这个问题的关键是需要动态决定需要创建的类,这不是设计模式能解决的问题属于软件平台的功能范畴。.NET可以提供相应的功能,即反射技术。
我们首先查看采用反射技术实现简化的实例:

None.gif Imports  System.Reflection
ExpandedBlockStart.gifContractedBlock.gif
Public   Class CreateVehicleByType Class CreateVehicleByType
InBlock.gif
Implements CreateVehicle
InBlock.gif
InBlock.gif
Private VeicleType As Type
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
Public Sub New()Sub New(ByVal t As Type)
InBlock.gifVeicleType 
= t
ExpandedSubBlockEnd.gif
End Sub

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
Public Function CreateAVehicle()Function CreateAVehicle() As Vehicle Implements
InBlock.gifCreateVehicle.CreateAVehicle
InBlock.gif           
Dim objConstructor As ConstructorInfo =
InBlock.gifVeicleType.GetConstructor(System.Type.EmptyTypes)
InBlock.gif           
Dim c As Vehicle = Ctype(objConstructou.Invoke(Nothing),Vehicle)
InBlock.gif           
Return c 
ExpandedSubBlockEnd.gif       
End Function

ExpandedBlockEnd.gif
End Class



在使用时,只要在创建时带入需要创建的类的类型:

    

ExpandedBlockStart.gif ContractedBlock.gif Private   Sub btcreateByType_Click() Sub btcreateByType_Click(ByVal sender As System.Object,ByVal e As
InBlock.gifSystem.EventArgs) 
Handles btCreateBytype.Clik
InBlock.gif    `根据选择创建一个交通工具并执行GO
InBlock.gif    
Dim v As Vehicle `我们不知道需要创建的具体交通工具
InBlock.gif    
Dim f As CreateVehicle
InBlock.gif    
If rCar.Checked Then
InBlock.gif        F 
= New CreateVehicleByType(GetType(car))
InBlock.gif    
End If
InBlock.gif    
If rTrain.Checked Then
InBlock.gif        F 
= New CreateVehicleByType(GetType(Train))
InBlock.gif    
End If
InBlock.gif    
If rBoat.Checked Then
InBlock.gif        F 
= New CreateVehicleByType(GetType(Boat))
InBlock.gif    
End If
InBlock.gif    
If rBus.Checked Then
InBlock.gif         F 
= New CreateVehicleByType(GetType(Boat))
InBlock.gif     
End If
InBlock.gif     V 
= f.CreateAVehicle
InBlock.gif     `执行GO指令
InBlock.gif     lbGO.Text 
= v.Go
ExpandedBlockEnd.gif  
End Sub

None.gif


         通过采用反射技术,我们将4个类简化为一个类,并且在新增类型时不需要新的创建这样,我们得到了简化的工厂,可以将其称为“反射工厂”。

3.对简单工厂的改进
         简单工厂通过参数决定创建的类型,这些参数是在编程时预设的。因此在编译后就无法修改,让我们回顾代码:
    
我们可以将这个工厂改造为反射工厂:

ExpandedBlockStart.gif ContractedBlock.gif      Public   Class clsCreateDB Class clsCreateDB
ExpandedSubBlockStart.gifContractedSubBlock.gif        
Public Shared Function CreateDB()Function CreateDB(ByVal strType As stringByVal strConnString AsString) As _ clsAbstractDB
InBlock.gif            
Select Case strType.ToUpper
InBlock.gif                
Case “ORACLE”
InBlock.gif                    
Dim myOracle As clsoracleDB
InBlock.gif                    MyOracle 
= New clsOracleDB(strConnString)
InBlock.gif                    
Return myOracle
InBlock.gif                
Case “SQLSERVER”
InBlock.gif                    
Dim mysqlserver As clsSQLServerDB
InBlock.gif                    Mysqlserver 
= New clsSQLServerDB(strConnString)
InBlock.gif                    
Return mysqlserver
InBlock.gif                
Case Else
InBlock.gif                    
Dim myoledb As clsOLEDB
InBlock.gif                    Myoledb 
= New clsOLEDB(strConnString)
InBlock.gif                    
Return myoledb
InBlock.gif             
End Select
ExpandedSubBlockEnd.gif         
End Function

ExpandedBlockEnd.gif     
End Class

None.gif


      
         这样解决了简单工厂必须依赖每个具体产品的问题,将表态依赖变为动态绑定.当引入新的数据库类型时,不需要修改工厂即可满足需要。 

4.反射与工厂方法
        如果工厂方法仅仅是为了获得某个产品的实例,那么完全可以使用反射技术来实现工厂方法。这样解决了工厂方法的潜在问题,即当增加产品类时,必须增加相应的子类。
         然而当工厂方法所存在的类不仅是实例化产品时,采用反射不一定是好办法,因为可能使问题变得复杂。

5.反射与抽象工厂
         可以采用反射来实现抽象工厂,这时抽象工厂可能变成了使用反射技术的具体工厂,不再有子类存在。创建交通系统的实例可以用如下的代码来写:

None.gif
None.gif
' <summary>
None.gif'
VehicleSystemReflectionFactory 采用反射技术的工厂。
None.gif'
</summary>
ExpandedBlockStart.gifContractedBlock.gif
Public   Class VehicleSystemReflectionFactory Class VehicleSystemReflectionFactory
InBlock.gif    
Dim vehicleType As String
InBlock.gif    
Dim vehicleStationType As String
ExpandedSubBlockStart.gifContractedSubBlock.gif    
Public Sub New()Sub New(ByVal vt As StringByVal vst As String)
InBlock.gif        
Me.vehicleType = vt
InBlock.gif        
Me.vehicleStationType = vst
ExpandedSubBlockEnd.gif    
End Sub

ExpandedSubBlockStart.gifContractedSubBlock.gif    
Public Function GetVehicle()Function GetVehicle() As Vehicle
InBlock.gif        
Return CType(createbytype(Me.vehicleType), Vehicle)
ExpandedSubBlockEnd.gif    
End Function

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif    
Public Function GetVehicleStation()Function GetVehicleStation() As VehicleStation
InBlock.gif        
Return CType(createbytype(Me.vehicleStationType), VehicleStation)
ExpandedSubBlockEnd.gif    
End Function

ExpandedSubBlockStart.gifContractedSubBlock.gif    
Private Function createbytype()Function createbytype(ByVal vt As StringAs Object
InBlock.gif        
Dim tt As Type
InBlock.gif        tt 
= Type.GetType(vt)
InBlock.gif        
Dim ci As ConstructorInfo
InBlock.gif        ci 
= tt.GetConstructor(System.Type.EmptyTypes)
InBlock.gif        
Dim null As System.DBNull
InBlock.gif        
Return ci.Invoke(null)
ExpandedSubBlockEnd.gif    
End Function

InBlock.gif
ExpandedBlockEnd.gif
End Class

None.gif


这种情况下,抽象工厂就变为了只有一个类的反射工厂。

6.反射工厂的使用效果
         使用反射工厂的优点是极大地减少了工厂类的数量、降低了代码的冗余,并且系统更容易扩展,在增加新类型后,不需要修改工厂类。
         使用反射工厂的代价是工厂与产品之间的依赖关系不明显,由于是动态绑定,因此理论上可以用一个工厂完成很多类型的实例化,从而使得代码 不容易理解。另外增大了测试难度,创建是动态完成的,测试用例的编写和测试执行要比传统的工厂困难。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值