在使用一個類型的時候需要涉及到目標類型的實例化問題,在這里就閑侃一下。
有些講述設計模式或者設計原則等內容的書籍上,建議我們:“將客戶端和目標類型的實例化邏輯進行解耦”,這樣客戶端就不需要負責如何實例化的職責了,隱含的意思就是封裝實例化的過程。這里的關鍵點是,如果實例化過程本身非常簡單自然,例如一個簡單的new調用,是不需要進行額外的技巧性封裝的,也就更沒有必要引入一個第三方的角色來承擔實例化過程(例如工廠角色等)。
客戶端兩種獲取實例的方式:

【不需要第三者引入】
既然要對實例化過程進行封裝,并進而引入一個中間角色負責實例化的職責,那么如果實例化過程本身非常簡單,干嗎還需要引入一個第三方角色來負責實例化呢???
對于這種情況下,應該是蠻簡單的,那就是通過構造函數或者靜態方法接口獲取實例。
1、普通構造函數。這是語言內置支持的,每個人應該都很熟悉了,就不羅唆說明了
2、靜態接口獲取實例的方式。遵照《重構與模式》一書中的說法,這種靜態方法暫且成為“creation method”吧。引入這種方式一般有什么必須的理由呢:
1、構造函數的選擇使用有一定的復雜度,例如構造函數過多、參數較多、構造函數本身有點難以理解(這往往是該類型代表的概念就有點難以理解^_^)等情況,針對一些常用的典型的場景提供幾個靜態獲取實例的接口應該是對客戶很有利的。例如你創建一個Color類型,提供了構造函數雖然并不復雜,就是RGB三種數值,那可能順便提供幾種便利的靜態接口,例如提供系統的紅、黃、藍等顏色等。關于這種方式,有一個極大的負作用,那就是提供了非標準的創建實例的方式,這種方式并不能被繼承等。
2、可能限制實例化過程,并且往往伴隨著管理實例。例如相應的創建型如單件(singleton)、多件等等。這個大家應該也已經很熟悉了,就不說了^_^ 只是提醒一點,那就是要判斷是否真的需要做這種限制,是否需要Class.newInstance的調用場景等。
3、通過靜態接口提供子類型實例。這通常體現在返回的是本類型,但是真正的實現類型可能不是該類型的子類型,而又不想將改類型暴露給用戶,希望用戶同一使用該父類型進行操作。這種實現方式對外是自然的,也符合依賴倒置等原則;對內可能就是不自然的,畢竟是父類型知道了子類型的存在。
【引入第三者負責實例化職責】
引入的具體角色和意圖的不同而不同,一般常用的如下:
1、實例化的過程本身并不會變化,在需要中這種創建過程就是具體的而不是一個變化的點。這種,一般引入一個靜態工廠方法就可以了
2、如果實例化的過程變化,那就需要封裝,暫且不考慮是何種變化。在面向對象設計中,一般遇到變化的點就是將其抽象封裝,進而產生一個抽象概念,然后在應用上下文中以引用的方式來使用這個概念。那好了,如果要封裝的是單一類型實例化過程的變化,那么就是常用的factory method;同理,如果需要面對的是創建系列類型實例化過程的變化,則就使用abstract factory(可以將其視為增強型的factory method^_^);如果這種變化不是正對類型,而是單純針對實例化過程中步驟的,那么用builder來處理一下吧。
第三者的引入,自然會引入一定的復雜性,尤其是對于那些不熟悉設計模式的開發人員而言(例如,factory的引入必然會隱藏掉具體類型,這對那些不是很習慣面向抽象類型編程的開發者而言,很有可能就會覺得不自然^_^ )。還有的就是,不恰當的引入效果遠不如不引入,引入之前一定要給自己一個充足的理由。 其實,這一點也同時適用于所有設計模式、設計技巧等的使用。
【總結】
總結起來就幾個提問,對實例過程進行處理的時候需要問自己的問題:
1、是否需要為實例化過程引入第三者,引入的理由是什么?
2、如果不需要引入,需要對語言提供的構造函數特性進行進一步的技巧性處理?
3、如果需要引入第三者,針對需要引入的理由,這個第三者的角色又是怎樣的?
本博客中的所有文章、隨筆除了標題中含有引用或者轉載字樣的,其他均為原創。轉載請注明出處,謝謝!