Dot NET設計模式—反射工廠

iDotNetSpace發表於2009-07-03
概述
        如果採用傳統方式實現了簡單工廠、工廠方法和抽象工廠在有些場合下如此處理,程式碼會變得冗餘並且難以維護。
        假設我們需要建立一種交通工具,可以是汽車、火車或者輪船,結構如圖所示。
Dot NET設計模式—反射工廠

  我們可以採用簡單工廠,通過引數指示建立所需要的物件型別。如果增加子類,例如卡車和轎車等,則必須增加引數的相應的程式碼。如果子類層次很多,則會使程式變得難以維護如果用簡單工廠實現上面的結構,則顯然很煩瑣。
         當然我們可以採用工廠方法來實現,即定義一個產生交通工具的介面,然後在子類中實現建立具體的子類。程式碼如下:
採用介面定義了抽象的工廠方法
 

Dot NET設計模式—反射工廠public Interface CreateVehicle
Dot NET設計模式—反射工廠     
Function CreateAVehicle() As Vehicle `建立一個交通工具
Dot NET設計模式—反射工廠
End Interface

Dot NET設計模式—反射工廠` 具體的建立由子類決定
Dot NET設計模式—反射工廠
public Class CreateCar
Dot NET設計模式—反射工廠    
Implements CreateCar
Dot NET設計模式—反射工廠    
Public Function CreateAVheicle() AsVehicle Implements
Dot NET設計模式—反射工廠CreateVehicle.CreateAVehicle
Dot NET設計模式—反射工廠        
Return New Car
Dot NET設計模式—反射工廠     
End Function

Dot NET設計模式—反射工廠
End Class


        這就是工廠方法。如果我們希望增加一個新的交通工具,不僅需要實現工具介面,還需要實現產生交通工具的工廠方法。下面是船的具體工廠方法:

Dot NET設計模式—反射工廠   Public Class CreateBoat
Dot NET設計模式—反射工廠       
Implements CreateVehicle
Dot NET設計模式—反射工廠       
Public Function CreateAVehicle() As Vehicle Implements
Dot NET設計模式—反射工廠CreateVehicle.CreateAVehicle
Dot NET設計模式—反射工廠            
Return New Boat
Dot NET設計模式—反射工廠       
End Function

Dot NET設計模式—反射工廠    
End Class


        顯然,如果我們需要產生數十種交通工具則需要有數十個具體的工廠類。而這些工廠類的區別僅僅是返回相應的類的例項,所以為維護帶來了麻煩。如果需要在介面中增加一個帶引數的建立方法則所有的子類都不得需要修改。
在這個場合下,採用抽象工廠與工廠方法沒有區別。因為這裡並不涉及產品線,抽象工廠並不能解決其中有的問題。當然,如果每種交通工具都要有對應的車站,則要使用抽象工廠,但是將會更復雜。      

2.採用反射技術簡化工廠類
        有沒有可能將需要建立類的型別傳遞到工廠方法中,由工廠方法根據型別返回相應的例項?
        解決這個問題的關鍵是需要動態決定需要建立的類,這不是設計模式能解決的問題屬於軟體平臺的功能範疇。.NET可以提供相應的功能,即反射技術。
我們首先檢視採用反射技術實現簡化的例項:

Dot NET設計模式—反射工廠Imports System.Reflection
Dot NET設計模式—反射工廠
Public Class CreateVehicleByType
Dot NET設計模式—反射工廠
Implements CreateVehicle
Dot NET設計模式—反射工廠
Dot NET設計模式—反射工廠
Private VeicleType As Type
Dot NET設計模式—反射工廠
Dot NET設計模式—反射工廠
Public Sub New(ByVal t As Type)
Dot NET設計模式—反射工廠VeicleType 
= t
Dot NET設計模式—反射工廠
End Sub

Dot NET設計模式—反射工廠
Dot NET設計模式—反射工廠
Public Function CreateAVehicle() As Vehicle Implements
Dot NET設計模式—反射工廠CreateVehicle.CreateAVehicle
Dot NET設計模式—反射工廠           
Dim objConstructor As ConstructorInfo =
Dot NET設計模式—反射工廠VeicleType.GetConstructor(System.Type.EmptyTypes)
Dot NET設計模式—反射工廠           
Dim c As Vehicle = Ctype(objConstructou.Invoke(Nothing),Vehicle)
Dot NET設計模式—反射工廠           
Return c 
Dot NET設計模式—反射工廠       
End Function

Dot NET設計模式—反射工廠
End Class



在使用時,只要在建立時帶入需要建立的類的型別:

    

Dot NET設計模式—反射工廠Private Sub btcreateByType_Click(ByVal sender As System.Object,ByVal e As
Dot NET設計模式—反射工廠System.EventArgs) 
Handles btCreateBytype.Clik
Dot NET設計模式—反射工廠    `根據選擇建立一個交通工具並執行GO
Dot NET設計模式—反射工廠    
Dim v As Vehicle `我們不知道需要建立的具體交通工具
Dot NET設計模式—反射工廠    
Dim f As CreateVehicle
Dot NET設計模式—反射工廠    
If rCar.Checked Then
Dot NET設計模式—反射工廠        F 
= New CreateVehicleByType(GetType(car))
Dot NET設計模式—反射工廠    
End If
Dot NET設計模式—反射工廠    
If rTrain.Checked Then
Dot NET設計模式—反射工廠        F 
= New CreateVehicleByType(GetType(Train))
Dot NET設計模式—反射工廠    
End If
Dot NET設計模式—反射工廠    
If rBoat.Checked Then
Dot NET設計模式—反射工廠        F 
= New CreateVehicleByType(GetType(Boat))
Dot NET設計模式—反射工廠    
End If
Dot NET設計模式—反射工廠    
If rBus.Checked Then
Dot NET設計模式—反射工廠         F 
= New CreateVehicleByType(GetType(Boat))
Dot NET設計模式—反射工廠     
End If
Dot NET設計模式—反射工廠     V 
= f.CreateAVehicle
Dot NET設計模式—反射工廠     `執行GO指令
Dot NET設計模式—反射工廠     lbGO.Text 
= v.Go
Dot NET設計模式—反射工廠  
End Sub

Dot NET設計模式—反射工廠


         通過採用反射技術,我們將4個類簡化為一個類,並且在新增型別時不需要新的建立這樣,我們得到了簡化的工廠,可以將其稱為“反射工廠”。

3.對簡單工廠的改進
         簡單工廠通過引數決定建立的型別,這些引數是在程式設計時預設的。因此在編譯後就無法修改,讓我們回顧程式碼:
     
我們可以將這個工廠改造為反射工廠:

Dot NET設計模式—反射工廠    Public Class clsCreateDB
Dot NET設計模式—反射工廠        
Public Shared Function CreateDB(ByVal strType As stringByVal strConnString AsString) As _ clsAbstractDB
Dot NET設計模式—反射工廠            
Select Case strType.ToUpper
Dot NET設計模式—反射工廠                
Case “ORACLE”
Dot NET設計模式—反射工廠                    
Dim myOracle As clsoracleDB
Dot NET設計模式—反射工廠                    MyOracle 
= New clsOracleDB(strConnString)
Dot NET設計模式—反射工廠                    
Return myOracle
Dot NET設計模式—反射工廠                
Case “SQLSERVER”
Dot NET設計模式—反射工廠                    
Dim mysqlserver As clsSQLServerDB
Dot NET設計模式—反射工廠                    Mysqlserver 
= New clsSQLServerDB(strConnString)
Dot NET設計模式—反射工廠                    
Return mysqlserver
Dot NET設計模式—反射工廠                
Case Else
Dot NET設計模式—反射工廠                    
Dim myoledb As clsOLEDB
Dot NET設計模式—反射工廠                    Myoledb 
= New clsOLEDB(strConnString)
Dot NET設計模式—反射工廠                    
Return myoledb
Dot NET設計模式—反射工廠             
End Select
Dot NET設計模式—反射工廠         
End Function

Dot NET設計模式—反射工廠     
End Class

Dot NET設計模式—反射工廠


      
         這樣解決了簡單工廠必須依賴每個具體產品的問題,將表態依賴變為動態繫結.當引入新的資料庫型別時,不需要修改工廠即可滿足需要。 

4.反射與工廠方法
        如果工廠方法僅僅是為了獲得某個產品的例項,那麼完全可以使用反射技術來實現工廠方法。這樣解決了工廠方法的潛在問題,即當增加產品類時,必須增加相應的子類。
         然而當工廠方法所存在的類不僅是例項化產品時,採用反射不一定是好辦法,因為可能使問題變得複雜。

5.反射與抽象工廠
         可以採用反射來實現抽象工廠,這時抽象工廠可能變成了使用反射技術的具體工廠,不再有子類存在。建立交通系統的例項可以用如下的程式碼來寫:

Dot NET設計模式—反射工廠
Dot NET設計模式—反射工廠
'
Dot NET設計模式—反射工廠'
VehicleSystemReflectionFactory 採用反射技術的工廠。
Dot NET設計模式—反射工廠'

Dot NET設計模式—反射工廠
Public Class VehicleSystemReflectionFactory
Dot NET設計模式—反射工廠    
Dim vehicleType As String
Dot NET設計模式—反射工廠    
Dim vehicleStationType As String
Dot NET設計模式—反射工廠    
Public Sub New(ByVal vt As StringByVal vst As String)
Dot NET設計模式—反射工廠        
Me.vehicleType = vt
Dot NET設計模式—反射工廠        
Me.vehicleStationType = vst
Dot NET設計模式—反射工廠    
End Sub

Dot NET設計模式—反射工廠    
Public Function GetVehicle() As Vehicle
Dot NET設計模式—反射工廠        
Return CType(createbytype(Me.vehicleType), Vehicle)
Dot NET設計模式—反射工廠    
End Function

Dot NET設計模式—反射工廠
Dot NET設計模式—反射工廠    
Public Function GetVehicleStation() As VehicleStation
Dot NET設計模式—反射工廠        
Return CType(createbytype(Me.vehicleStationType), VehicleStation)
Dot NET設計模式—反射工廠    
End Function

Dot NET設計模式—反射工廠    
Private Function createbytype(ByVal vt As StringAs Object
Dot NET設計模式—反射工廠        
Dim tt As Type
Dot NET設計模式—反射工廠        tt 
= Type.GetType(vt)
Dot NET設計模式—反射工廠        
Dim ci As ConstructorInfo
Dot NET設計模式—反射工廠        ci 
= tt.GetConstructor(System.Type.EmptyTypes)
Dot NET設計模式—反射工廠        
Dim null As System.DBNull
Dot NET設計模式—反射工廠        
Return ci.Invoke(null)
Dot NET設計模式—反射工廠    
End Function

Dot NET設計模式—反射工廠
Dot NET設計模式—反射工廠
End Class

Dot NET設計模式—反射工廠


這種情況下,抽象工廠就變為了只有一個類的反射工廠。

6.反射工廠的使用效果
         使用反射工廠的優點是極大地減少了工廠類的數量、降低了程式碼的冗餘,並且系統更容易擴充套件,在增加新型別後,不需要修改工廠類。
         使用反射工廠的代價是工廠與產品之間的依賴關係不明顯,由於是動態繫結,因此理論上可以用一個工廠完成很多型別的例項化,從而使得程式碼 不容易理解。另外增大了測試難度,建立是動態完成的,測試用例的編寫和測試執行要比傳統的工廠困難。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-608292/,如需轉載,請註明出處,否則將追究法律責任。

相關文章