天天看點

【Java設計模式系列】工廠方法模式(下)

4.2 更新為多個工廠類

當我們在做一個比較複雜的項目時,經常會遇到初始化一個對象很耗費精力的情況,所有的産品類都放到一個工廠方法中進行初始化會使代碼結構不清晰

例如,一個産品類有5個具體實作,每個實作類的初始化(不僅僅是new,初始化包括new一個對象,并對對象設定一定的初始值)方法都不相同,如果寫在一個工廠方法中,勢必會導緻該方法巨大無比,那該怎麼辦?

考慮到需要結構清晰,我們就為每個産品定義一個創造者,然後由調用者自己去選擇與哪個工廠方法關聯

我們還是以女娲造人為例,每個人種都有一個固定的八卦爐,分别造出黑色人種、白色人種、黃色人種

【Java設計模式系列】工廠方法模式(下)

每個人種(具體的産品類)都對應了一個建立者,每個建立者都獨立負責建立對應的産品對象,非常符合單一職責原則,看看代碼變化

【Java設計模式系列】工廠方法模式(下)
  • 抽象方法中已經不再需要傳遞相關參數了,因為每一個具體的工廠都已經非常明确自己的職責:建立自己負責的産品類對象。
  • 黑色人種的建立工廠實作
  • 【Java設計模式系列】工廠方法模式(下)
  • 黃色人種的建立類
  • 【Java設計模式系列】工廠方法模式(下)
  • 白色人種的建立類
  • 【Java設計模式系列】工廠方法模式(下)
  • 三個具體的建立工廠都非常簡單,但是,如果一個系統比較複雜時工廠類也會相應地變複雜。
  • 場景類NvWa修改後的代碼
  • 【Java設計模式系列】工廠方法模式(下)
  • 運作結果還是相同

每一個産品類都對應了一個建立類,好處就是建立類的職責清晰,而且結構簡單,但是給可擴充性和可維護性帶來了一定的影響。為什麼這麼說呢?如果要擴充一個産品類,就需要建立一個相應的工廠類,這樣就增加了擴充的難度。因為工廠類和産品類的數量相同,維護時需要考慮兩個對象之間的關系。

當然,在複雜的應用中一般采用多工廠的方法,然後再增加一個協調類,避免調用者與各個子工廠交流,協調類的作用是封裝子工廠類,對高層子產品提供統一的通路接口。

4.3 替代單例模式

單例模式的核心要求就是

在記憶體中隻有一個對象

,通過工廠方法模式也能隻在記憶體中生産一個對象。

  • 工廠方法模式替代單例模式類圖
  • 【Java設計模式系列】工廠方法模式(下)
  • Singleton定義了一個private的無參構造函數,目的是不允許通過new的方式建立一個對象
  • 單例類
  • 【Java設計模式系列】工廠方法模式(下)
  • Singleton保證不能通過正常的管道建立一個對象

那SingletonFactory如何建立一個單例對象呢?

反射!

  • 負責生成單例的工廠類
  • 【Java設計模式系列】工廠方法模式(下)
  • 通過獲得類構造器,然後設定private通路權限,生成一個對象,然後提供外部通路,保證記憶體中的對象唯一。

以上通過工廠方法模式建立了一個單例對象,該架構可以繼續擴充,在一個項目中可以産生一個單例構造器,所有需要産生單例的類都遵循一定的規則(構造方法是private),然後通過擴充該架構,隻要輸入一個類型就可以獲得唯一的一個執行個體。

3.4 延遲初始化(Lazy initialization)

一個對象被消費完畢後,并不立刻釋放,工廠類保持其初始狀态,等待再次被使用

延遲初始化是工廠方法模式的一個擴充應用

  • 延遲初始化的通用類圖
  • 【Java設計模式系列】工廠方法模式(下)
  • ProductFactory負責産品類對象的建立工作,并且通過prMap變量産生一個緩存,對需要再次被重用的對象保留
  • 延遲加載的工廠類
  • 【Java設計模式系列】工廠方法模式(下)
  • 通過定義一個Map容器,容納所有産生的對象,如果在Map容器中已經有的對象,則直接取出傳回;如果沒有,則根據需要的類型産生一個對象并放入到Map容器中,以友善下次調用。

延遲加載架構是可以擴充的,例如限制某一個産品類的最大執行個體化數量,可以通過判斷Map中已有的對象數量來實作,這樣的處理是非常有意義的,例如JDBC連接配接資料庫,都會要求設定一個MaxConnections最大連接配接數量,該數量就是記憶體中最大執行個體化的數量。

延遲加載還可以用在對象初始化比較複雜的情況下,例如硬體通路,涉及多方面的互動,則可以通過延遲加載降低對象的産生和銷毀帶來的複雜性。