設計模式綜合實戰項目x-gen 系列三
1.1 實現起點
為了讓大家更好的理解配置管理模塊的內部實現架構,因此先以一個最簡單的實現結構為起點,采用重構的方式,逐步把相關的設計模式應用進來,從簡單到復雜,從而讓大家更好的看到如何選擇要使用的設計模式、如何實際應用設計模式以及如何讓多種設計模式協同工作。
1.1.1 先就來看看實現配置管理的起點,首先根據對外提供的數據結構定義,制作出相應的數據model來。
(1)先來看看如何描述GenConf.xml中的NeedGen,對應的xml片斷如下:
<NeedGen id="UserGenConf" provider="XmlModuleGenConf" themeId="simple">
<Param id="fileName">UserGenConf.xml</Param>
</Params>
</NeedGen>
根據定義可以設計出如下的數據model,代碼如下:
/
描述需要被生成模塊的註冊信息
/
publicclass NeedGenModel {
/
需要被生成模塊的標識
/
private String id;
/
用來讀取並解析需要被生成模塊的配置文件的程序標識
/
private String provider;
/
需要被生成模塊使用的theme
/
private String theme;
/*
需要被生成模塊需要的一些參數,通常是給provider使用的
private Map<String,String> mapParams = new HashMap<String,String>();
//getter/setter 省略了
}
(2)然後看看ThemeModel,會涉及到GenTypeModel,先看看GenType對應的xml片斷,示例如下:
<GenType id="GenBusinessEbi" type="cn.javass.themes.simple.actions.GenBusinessEbiAction">
<Params>
<Param id="relativePath">business.ebi</Param>
<Param id="preGenFileName"></Param>
<Param id="afterGenFileName">Ebi.java</Param>
</Params>
</GenType>
那麽,根據定義設計出對應的model,示例如下:
/
主題提供的能生成的功能類型
/
publicclass GenTypeModel {
/
能生成的功能類型的標識
/
private String id;
/
具體用來生成功能的類
/
private String genTypeClass;
/
生成功能所需要的參數,key:參數標識,value:參數值
/
private Map<String,String> mapParams = new HashMap<String,String>();
//getter/setter 省略了
}
(3)接下來看看theme對應的數據模型,根據定義設計出對應的model,示例如下:
/
主題的數據模型
/
publicclass ThemeModel {
/
主題的標識
/
private String id ="";
/
主題的存放位置,從GenConf傳遞過來
/
private String location = "";
/
主題提供的能生成功能的類型,key:類型的標識,value:描述生成類型的model
/
private Map<String,GenTypeModel> mapGenTypes = new HashMap<String,GenTypeModel>();
/
主題提供的輸出類型,key:輸出類型的標識,value:實現輸出類型的類
/
private Map<String,String> mapGenOutTypes = new HashMap<String,String>();
/
主題提供的讀取配置文件的provider,key:provider的標識,value:實現provider的類
/
private Map<String,String> mapProviders = new HashMap<String,String>();
//getter/setter 省略了
}
(4)接下來看看GenConfModel,綜合前面兩個,示例如下:
/
x-gen核心框架配置對應的model
/
publicclass GenConfModel {
/
描述註冊的多個需要生成的模塊model
/
private List<NeedGenModel> needGens = new ArrayList<NeedGenModel>();
/
描述註冊的多個主題的model
/
private List<ThemeModel> themes = new ArrayList<ThemeModel>();
/
通用的一些常量定義,key:常量的標識,value:常量的值
/
private Map<String,String> mapConstants = new HashMap<String,String>();
/**
*根據theme的id來獲取相應theme的配置數據
*@paramthemeId
*@return
*/
public ThemeModel getThemeById(String themeId){
for(ThemeModel tm : themes){
if(tm.getId().equals(themeId)){
return tm;
}
}
returnnew ThemeModel();
}
//getter/setter 省略了
}
(5)然後再看ModuleConfModel,會涉及到ExtendConfModel,先來看看ExtendConfModel對應的xml片斷,示例如下:
<ExtendConf id="moduleName" isSingle="true">user</ExtendConf>
那麽,根據定義設計出對應的model,示例如下:
/
模塊配置中擴展數據的model
/
publicclass ExtendConfModel {
/
擴展數據的標識
/
private String id="";
/
描述數據是單個值還是多個值
/
privatebooleansingle = true;
/
描述單個值
/
private String value="";
/*
描述多個值
*/
private String values[] = null;
//getter/setter 省略了
}
(6)然後來看ModuleConfModel,示例如下:
/
描述模塊配置的數據model
/
publicclass ModuleConfModel {
/
模塊標識
/
private String moduleName = "";
/
模塊生成所使用的主題的標識
/
private String useTheme = "";
/
模塊生成所需要的擴展數據
/
private Map<String,ExtendConfModel> mapExtends = new HashMap<String,ExtendConfModel>();
/*
模塊需要生成的功能,key:需要生成功能的標識,value:多種輸出類型的標識的集合
*/
private Map<String,List<String>> mapNeedGenTypes = new HashMap<String,List<String>>();
//getter/setter 省略了
}
1.2 針對前面定義的API,提供一個最基本的實現,只需要滿足最基本的功能就可以了,需要實現讀取配置文件的功能,然後要有緩存配置數據的功能,最後就是實現API中要求的功能。
根據這些要求,可以寫出如下的示意代碼來:
/
示意實現:初步實現配置管理
/
publicclass GenConfEbo implements GenConfEbi {
/
用來存放核心框架配置的model
/
private GenConfModel genConf = new GenConfModel();
/*
用來存放需要生成的每個模塊對應的配置model
key:每個需要生成的模塊標識
value:每個需要生成的模塊對應的配置model
*/
private Map<String, ModuleConfModel> mapModuleConf = new HashMap<String, ModuleConfModel>();
public GenConfEbo(){
//在這裏就讀取配置數據
}
privatevoid readConf(){
//1:獲取配置的數據,比如讀取配置文件
//為了示意簡單,省略了
//2:把獲取到的配置數據設置到屬性裏面,緩存起來
}
/*以下的方法為對外接口的基本實現,大家仔細觀察會發現,其實只要讀取到了配置的數據,
這些實現基本上就是在內存裏面,進行很簡單的數據獲取存在*/
public GenConfModel getGenConf() {
returnthis.genConf;
}
public Map<String, ModuleConfModel> getMapModuleConf() {
returnthis.mapModuleConf;
}
public ExtendConfModel getModuleExtend(ModuleConfModel moduleConf,
String extendId) {
return moduleConf.getMapExtends().get(extendId);
}
public String getThemeGenOutType(ModuleConfModel moduleConf,
String genOutTypeId) {
returnthis.genConf.getThemeById(
moduleConf.getUseTheme()).getMapGenOutTypes().get(genOutTypeId);
}
public GenTypeModel getThemeGenType(ModuleConfModel moduleConf,
String genTypeId) {
returnthis.genConf.getThemeById(
moduleConf.getUseTheme()).getMapGenTypes().get(genTypeId);
}
}
2 加入簡單工廠
2.1 面臨的問題
觀察上面的實現,向模塊外部提供了接口,可是外部根本不知道模塊內部的具體實現,那麽模塊外部如何來獲取一個實現接口的實現對象呢?
2.2 用簡單工廠來解決
簡單工廠是解決上述問題的一個合理方案。那麽先一起來回顧一下簡單工廠的一些基礎知識,然後再來看如何應用它來解決上面的問題。
2.2.1 簡單工廠基礎回顧
1:模式定義
提供一個創建對象實例的功能,而無須關心其具體實現。被創建實例的類型可以是接口、抽象類,也可以是具體的類。
2:模式本質
簡單工廠的本質是:選擇實現。
3:模式結構
圖 簡單工廠的結構示意圖
4:基礎知識
(1)簡單工廠位於對外提供接口的模
(2)簡單工作的主要功能就是用來創建對象實例,被創建的對象可以是接口、抽象類或是普通的類
(3)簡單工廠可以實現成為單例,也可以實現成靜態工廠
(4)簡單工廠的內部實現,主要是做“選擇合適的實現”,實現是已經做好的,簡單工廠只是來選擇使用即可
(5)簡單工廠在進行選擇的時候,需要的參數可以從客戶端傳入、配置文件、或者是運行期程序某個運行結果等
(6)如果使用反射+配置文件的方式,可以寫出通用的簡單工廠
5:常見應用場景:
通常使用簡單工廠來對模塊外部提供接口對象,這樣可以有效隱藏模塊內部實現。
2.2.2 使用簡單工廠來解決問題的思路
簡單工廠解決這個問題的思路就是,在配置管理模塊裏面添加一個類,在這個類裏面實現一個方法,讓這個方法來創建一個接口對象並返回然後把這個類提供給客戶端,讓客戶端通過調用這個類的方法來獲取接口對象。
2.2.3 核心代碼示例
制作一個簡單工廠,示例如下:
publicclass GenConfFactory {
private GenConfFactory(){
}
publicstatic GenConfEbi createGenConfEbi(){
returnnew GenConfEbo();
}
}
小結
有了對外的接口和數據對象,自然需要提供工廠,來讓外部通過工廠獲取相應的接口對象,從而有效地隱藏內部實現。
到此就把對模塊外的結構定義好了,接下來就專心於模塊內部的實現了。
本文由微信公眾號——架構設計一起學 推出,
可點擊“閱讀原文“了解更多!
設計模式綜合實戰項目x-gen 系列三