就他吧-9ta8为您提供:身份证查询、15位转16位身份证,手机号码归属地查询,IP地址查询服务,城市天气预报查询,列车时刻表简易快速查询等等查询服务,就他吧欢迎您的光临!!
随笔- 96  评论- 750  文章- 16 

Dot NET设计模式—反射工厂

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

 

posted on 2005-08-03 09:05 振河 阅读(...) 评论(...) 编辑 收藏

  就他吧-9ta8伴您开心每一天