天天看點

設計模式系列之三:抽象工廠模式抽象工廠模式實作

前言

在設計模式有三個模式是與工廠模式相關的,分别是:簡單工廠模式、工廠方法模式以及抽象工廠模式。在前面的文章中已經談到前面兩種,這裡就對抽象工廠模式介紹一下。抽象工廠模式就是提供一個建立一系列相關或者互相依賴的接口(也就是抽象類),而無需指定具體的類。簡單來說,就是當我們需要建立一個具體的對象的時候,我們不必指定該具體的對象,隻需要使用它的上層接口直接調用就行。好像還是很抽象哦,好吧,為了更清晰領悟這個設計模式,我們還是通過一個案例來說明

某公司開發了一個a軟體,資料庫使用的是sqlserver。後由于客戶要求需要使用oracle資料庫,原來的資料要遷移到oracle中,在遷移的過程中遇到很多問題,比如文法錯誤,關鍵字濫用,函數不支援等問題。請設計一組程式,實作資料的無縫遷移。

通過使用我們的工廠方法模式,我們已經較好的解決了使用者使用不同資料庫的問題,現在我們已經獲得了要建立的資料庫對象,那麼接下來我們就需要向資料庫中添加資料了,假設都需要添加部門資訊,有的使用者需要使用oracle,有的使用者需要使用sqlserver。考慮抽象工廠模式的代碼結構:

設計模式系列之三:抽象工廠模式抽象工廠模式實作

在修改代碼結構之前,為了更好的對比,來看一下我們現在的代碼結構:

設計模式系列之三:抽象工廠模式抽象工廠模式實作

原始代碼v1.0:

根據抽象工廠模式結構圖以及需求,修改代碼如下:

1) 增加一個建立部門的抽象工廠,這裡使用接口

2) 分别建立基于oracle以及基于sqlserver的部門實作類(已經在上面的代碼中實作)

3) 建立一個資料庫工具類,根據條件建立需要的對象

修改的代碼v1.1

這裡通過dbaccess類直接替代了原來的ifactory、oraclefactory、sqlserverfactory三個類,這裡實際上是簡單工廠的實作方法,把判斷邏輯轉移到dbaccess中,用戶端不需要做任何修改,要更換資料庫隻需要在dbaccess中把dbtype的值修改就ok。在這點上,好像簡單工廠占優勢,但是不盡然,如果要在程式中添加對mysql資料庫的支援,如果使用原來抽象工廠模式。隻需要添加一個mysqlfactory類就行,現在就需要在dbaccess類中修改邏輯判斷了(在這一點違背了封閉開放原則)。那麼有沒有一種方法,不要增加對switch的判斷就可以根據dbtype的值建立相應的對象呢?也就是說,在程式運作期間,根據類的字元串表示建立類的執行個體。答案是肯定的,在java中我們可以利用反射技術做到這一點,是以我們對v1.1版的代碼進行進一步的修改:

v1.2

現在,如果需要增加對mysql的支援隻需要修改oracle為mysql就行,不過還是得建立mysqlobject類以及mysqldepartment類,但是與上面簡單工廠模式的修改不同,這裡隻是在原來代碼的基礎增加,是擴充而不是修改。是以沒有違背開放-封閉原則,現在這版的代碼比之前好多了,但是dbtype的值仍然不可避免要進行修改,事實上還有一種通過配置檔案的方式可以儲存原來的代碼不變而實作這個功能,下面對代碼進行第三次修改:

首先建立db.properties配置檔案

v1.3版代碼

用戶端代碼保持不變,實際測試成功。

從v1.0到v1.3我們對工廠模式做一個簡單的小結:

所有使用簡單工廠的都可以考慮使用反射技術加以優化

抽象工廠的最大好處是便于交換産品系列,要建立不同的産品,我們可以使用不同的工廠建立。是以當我們需要不同産品線的産品的時候隻需要換一個工廠就可以輕松實作

抽象工廠模式與工廠方法模式把建立執行個體的過程與用戶端分離,使用者操作的隻是抽象接口,而具體的建立過程則封裝到了具體的工廠去實作。很好的展現了開放-封閉的原則

抽象工廠模式與抽象工廠模式都存在一個缺點,就是需要增加新功能的時候,要建立的類很多。

簡單工廠模式可以通過反射技術克服上訴缺點,但使用反射會降低程式的性能,是以雖然使用反避免了建立多個類的麻煩,卻也同時降低了程式的性能,所謂有得必有失。在實際的開發中還是需要仔細衡量的。