開閉原則:“對修改封閉,對擴充開放”。在物件導向的系統中,通過類的繼承實現擴充。.net中提供的partial class提供了擴充類的新思路。
一、應用情境
可以使用partial class的情境很多。這裡分析一個ORM的例子。
系統中有一個Cat類,屬性ID、Age、Weight都需要儲存到資料庫中,一個資訊系統中常見的需求。通過讀取資料庫的結構,可以用工具產生Cat類的代碼。並且ORM架構支援了從資料庫資訊產生Cat對象。
現在的Cat什麼動作都沒有,客戶說,我們需要一個Miaow()的函數。這時就需要對ORM產生的Cat類進行擴充了。
可以肯定地一點是,我們不能修改自動產生的程式碼,因為這會牽涉到資料庫結構與代碼同步的問題。解決這個需求有兩種方法:繼承方式擴充,partial class擴充。
二、繼承方式擴充
工具自動產生一個CatBase類,這個類只有屬性,嵌入到ORM架構中。既然需要擴充功能,很容易想到對這個基類繼承,於是有了Cat類。Cat類如願以償地有了Miaow()函數。
以前系統中用的是CatBase的執行個體,現在建立CatBase執行個體的地方需要改為建立Cat的執行個體。這個問題讓ORM架構解決吧。
客戶的需求實現了,我們自己的代碼產生也沒有遭到破壞,任務完成。
三、partial class擴充
partial class簡單地說就是可以將一個類的代碼寫到兩個或多個代碼檔案中。編譯器在編譯的過程中將這幾個檔案組合起來一起編譯。一個很酷的技術。
工具產生的Cat類仍然不變。既然需要增加函數,那麼在建立一個代碼檔案,將Miaow()函數寫出來就可以。需要做的僅僅是將類的聲明由class改為partial class,任務完成。
四、對比分析
兩種思路都可以實現需求。孰優孰劣需要仔細分析一下。
執行個體建立:partial class更加簡潔。
系統複雜度:對於系統來說,partial class方式下只存在一個類,而繼承方式有兩個類。
繼承邏輯:從邏輯上講,Cat並不需要一個基類CatBase,這樣做僅僅是因為在代碼構建過程中的一個限制。
維護性:兩種方式下都會存在兩個代碼檔案,維護成本並沒有區別。
可讀性:兩個Cat檔案確實讓人費解。
整體上說,使用partial class更加優雅一些。
“繼承”的這種方式比較符合傳統的思維習慣,而partial class到底是不是滿足開閉原則呢,這點確實不好說。不過在軟體構建上,我是一個實用主義者,哪種方式好用就用哪一種。
在ORM的情境中,partial class更加好一些,但有的時候,兩個類之間確實就存在繼承關係,那麼就必須用到繼承了。雖然絕大多數情況下,都需要繼承方式,但是既然有了partial class技術,我們在做設計時也需要考慮這個思路。
在VS2005中,Form、DataSet都使用了partial class方式,原理和這個一樣。但是要將這個原理推廣到“業務實體”中,可能在理解上需要有所突破。
使用partial class確實會帶來可讀性的損失,尤其是一個類分布在很多個檔案中的時候,所以檔案的命名最好是有一個規範來保證。