1 模块内部实现
1.1 实现起点
为了让大家更好的理解配置管理模块的内部实现架构,因此先以一个最简单的实现结构为起点,采用重构的方式,逐步把相关的设计模式应用进来,从简单到复杂,从而让大家更好的看到如何选择要使用的设计模式、如何实际应用设计模式以及如何让多种设计模式协同工作。
1.1.1 先就来看看实现配置管理的起点,首先根据对外提供的数据结构定义,制作出相应的数据model来。
(1)先来看看如何描述GenConf.xml中的NeedGen,对应的xml片断如下:
<NeedGen id="UserGenConf" provider="XmlModuleGenConf" themeId="simple">
<Params>
<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="mbPathFile">business/Ebi.txt</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();
}
}
|
小结
有了对外的接口和数据对象,自然需要提供工厂,来让外部通过工厂获取相应的接口对象,从而有效地隐藏内部实现。
到此就把对模块外的结构定义好了,接下来就专心于模块内部的实现了。