閆如海


摘要:文章針對傳統的抽象工廠模式的傾斜性進行了糾正,使得在生產不同產品族和不同產品等級結構時,新增產品等級結構不必修改源碼,給出符合開閉原則的設計方案,同時對抽象工廠的缺點做了改進設計,以適應系統設計時搭建上層框架的需求。
關鍵詞:抽象工廠模式;傾斜性;設計模式;開閉原則;系統設計 文獻標識碼:A
中圖分類號:TP312 文章編號:1009-2374(2015)33-0018-02 DOI:10.13535/j.cnki.11-4406/n.2015.33.010
1 概述
抽象工廠模式源于面向對象設計領域里的經典教材《設計模式》,顧名思義,抽象工廠模式用于系統運行時生產需要的對象,是一種創建型模式,在系統設計時是創建對象的核心模式。
對于使用抽象工廠模式增加新產品的等級結構,學者們普遍認為必須要修改所有的工廠角色,只能以修改源碼的方式新增新產品的等級結構,說明抽象工廠模式沒有很好支持開閉原則(OCP),以一種傾斜的方式支持增加新的產品,它為新產品族的增加提供方便,而不能為新的產品等級結構的增加提供這樣的方便。這種方式也已不能夠為制造業信息化和服務化服務,文中給出符合開閉原則的設計方案,同時對抽象工廠的缺點做了改進設計,以適應系統設計時搭建上層框架的需求。
2 新增產品等級結構的設計
如果已有產品等級A和B,產品族1和2,需要增加產品等級結構C可以按圖1所示進行:
圖1 新增產品等級結構的設計類圖
圖中新增兩大類內容,由虛線標注:
第一,新增的產品等級結構C位于圖下方,由三個類組成:AbstractProductC、ProductC1、ProductC2。其中ProductC1、ProductC2都繼承于AbstractProductC。
第二,工廠,這個是添加產品等級結構最重要的部分,由三部分組成:接口AbstractFactoryC1、類ConcreteFactoryC1、類ConcreteFactoryC2。
下面給出三個工廠的源碼:
工廠接口AbstractFactoryC.java
public interface AbstractFactoryC extends AbstractFactory{
AbstractProductC createProductC();
}
實現工廠ConcreteFactoryC1.java
public class ConcreteFactoryC1 extends ConcreteFactory1 implements AbstractFactoryC{
@Override
public AbstractProductC createProductC(){
return new ProductC1();
}
}
實現工廠ConcreteFactoryC2.java
public class ConcreteFactoryC2 extends ConcreteFactory2 implements AbstractFactoryC{
@Override
public AbstractProductC createProductC(){
return new ProductC2();
}
}
第一,新增的工廠接口AbstractFactoryC繼承于AbstractFactory,接口AbstractFactoryC內新增了生產產品等級結構C的方法CreateProductC(),返回的類型是產品等級C。
第二,新增兩個工廠類ConcreteFactoryC1和ConcreteFactoryC2,其中ConcreteFactoryC1繼承了ConcreteFactory1類,從上面可以知道,ConcreteFactory生產了產品族A1和B1,因為繼承的關系,ConcreteFactoryC1也有了這些功能。并且在類中生產了產品C1,支持了產品族1的生產。同理ConcreteFactoryC2也完成了產品族2的生產功能。
第三,完成客戶端的調用,如下:
public class Client{
public static void main(String[]args){
AbstractFactoryC cf1=new ConcreteFactoryC1();
cf1.createProductC();
AbstractFactoryC cf2=new ConcreteFactoryC2();
cf2.createProductC();
}
}
cf1能夠生產對象C1,cf2可以生產對象C2。從這個設計可以看出沒有改動圖1中任何接口和類的源碼,完全符合開閉原則(OCP),對系統內新增功能以新增類和接口方式完成。
3 抽象工廠模式改進設計
從以上內容可以看出抽象工廠模式并沒有在新增產品等級時的所謂傾斜性的問題,但是這種模式還是有一些別的問題。這里需要對這些問題進行改進:
第一,系統需要AbstractProduct產品的子類時無法完成任務。在上面的設計中能看出,AbstractFactory依賴AbstractProductA,ConcreteFactory1只負責生產AbstractProductA的子類ProductA,Client調用AbstractFactory后獲得AbstractProductA。如果Client需要ProductA繼承于AbstractProductA后新增的屬性或方法,這個模式就無法正常運行,而ProductA中肯定有自己新定義的方法和屬性,否則不需要新增子類,而且這些方法和屬性必定會在系統某個地方使用,那么以工廠類為唯一生產對象的入口設計方案還是需要進行改進。改進的方法就是引入泛型。
第二,新增產品等級結構時工廠一側的結構不易維護。上面的設計中新增產品等級C必須新加入抽象工廠AbstractFactoryC,再加入實現類ConcreteFactoryC1和ConcreteFactoryC2,產生了三個由繼承而來的類,繼承過多會造成耦合加劇,不利于維護。而且若新增次數增多則類規模會急速增大,產生很多冗余代碼。這個問題的根源在于工廠一側沒有進行抽象設計,僅僅簡單地做了方法提取。
下面就這兩個問題給出詳細的改進設計。
圖2 改進設計類圖
新增接口IProduct,AbstractProductA和AbstractProductB都繼承于它。這樣就出現一個產品的基接口。
引入泛型,修改AbstractFactory代碼如下:
public interface AbstractFactory
PRODUCT createProduct();
}
新增接口AbstractProductA:
public interface AbstractFactoryA
這個接口產生對產品A的泛型依賴,因為還是泛型,子類在實現這個接口時就可以生產出AbstractProductA的子類。
最后實現工廠ConcreteFactoryA,這里只給出生產A1產品的代碼,其余工廠類似,不再一一贅述。
public class ConcreteFactoryA implements AbstractFactoryA
@Override
public ProductA1 createProduct(){
return new ProductA1();
}
}
4 結語
本文通過對生產不同產品族和不同產品等級結構中新增產品等級結構的設計方案驗證了抽象工廠模式不必修改源碼也可以增加產品等級結構,同時也指出了相關設計時的注意事項,最后對抽象工廠的缺點做了改進
設計。
參考文獻
[1] Erich Gamma,李英軍,等.設計模式:可復用面向對象軟件的基礎[M].北京:機械工業出版社,2009.
[2] 閻宏.Java與模式[M].北京:電子工業出版社,2002.
[3] 王翔.設計模式:基于C#的工程化實現及擴展[M].北京:電子工業出版社,2009.
(責任編輯:周 瓊)