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:模式结构

 

设计模式组合模式架构源码分析 设计模式综合项目实战_ide

图 简单工厂的结构示意图

 

4:基础知识

 

  (1)简单工厂位于对外提供接口的模

 

  (2)简单工作的主要功能就是用来创建对象实例,被创建的对象可以是接口、抽象类或是普通的类

 

  (3)简单工厂可以实现成为单例,也可以实现成静态工厂

 

  (4)简单工厂的内部实现,主要是做“选择合适的实现”,实现是已经做好的,简单工厂只是来选择使用即可

 

  (5)简单工厂在进行选择的时候,需要的参数可以从客户端传入、配置文件、或者是运行期程序某个运行结果等

 

      (6)如果使用反射+配置文件的方式,可以写出通用的简单工厂

 

5:常见应用场景:

通常使用简单工厂来对模块外部提供接口对象,这样可以有效隐藏模块内部实现。

 

2.2.2 使用简单工厂来解决问题的思路

 

      简单工厂解决这个问题的思路就是,在配置管理模块里面添加一个类,在这个类里面实现一个方法,让这个方法来创建一个接口对象并返回然后把这个类提供给客户端,让客户端通过调用这个类的方法来获取接口对象。 

 

2.2.3  核心代码示例

制作一个简单工厂,示例如下:

publicclass GenConfFactory {
    private GenConfFactory(){
      
    }
    publicstatic GenConfEbi createGenConfEbi(){
       returnnew GenConfEbo();
    }
}

 小结

       有了对外的接口和数据对象,自然需要提供工厂,来让外部通过工厂获取相应的接口对象,从而有效地隐藏内部实现。

       到此就把对模块外的结构定义好了,接下来就专心于模块内部的实现了。