1.不用模式的解决方案
1.1 示例
开发一个三层结构(表现层,逻辑层,数据层)代码生成工具
(1)先看看描述配置的数据Model
public class ConfigModel {
private boolean needGenPresentation = true;
private boolean needGenBusiness = true;
private boolean needGenDAO = true;
public boolean isNeedGenPresentation(){
return needGenPresentation;
}
public boolean isNeedGenBusiness(){
return needGenBusiness;
}
public boolean isNeedGenDAO(){
return needGenDAO;
}
public void setNeedGenPresentation(boolean needGenPresentation) {
this.needGenPresentation = needGenPresentation;
}
public void setNeedGenBusiness(boolean needGenBusiness) {
this.needGenBusiness = needGenBusiness;
}
public void setNeedGenDAO(boolean needGenDAO) {
this.needGenDAO = needGenDAO;
}
}
(2)接着是配置管理
public class ConfigManager {
private static ConfigManager manager = null;
private static ConfigModel cm = null;
private ConfigManager(){
}
public static ConfigManager getInstance(){
if( manager == null){
manager = new ConfigManager();
cm = new ConfigModel();
}
return manager;
}
public ConfigModel getConfigData(){
return cm;
}
}
(3)再看看各个生成代码的模块,示例代码如下:
先来看表现层的示意实现
public class Presentation {
public void generate(){
//从配置管理中获取相应的配置信息
ConfigModel cm = ConfigManager.getInstance().getConfigData();
if(cm.isNeedGenPresentation()){
System.out.println("正在生成表现层代码文件");
}
}
}
再来看逻辑层的示意实现
public class Business {
public void generate(){
//从配置管理中获取相应的配置信息
ConfigModel cm = ConfigManager.getInstance().getConfigData();
if(cm.isNeedGenBusiness()){
System.out.println("正在生成逻辑层代码文件");
}
}
}
下面是数据层的示意实现
public class DAO {
public void generate(){
//从配置管理中获取相应的配置信息
ConfigModel cm = ConfigManager.getInstance().getConfigData();
if(cm.isNeedGenDAO()){
System.out.println("正在生成数据层代码文件");
}
}
}
(4)此时的客户端实现,就是去调用多个代码生成模块了,示意代码如下:
public class Client {
//为了生成代码,客户端需要对三个模块都要了解,知道要如何生成才可,耦合度太高
public static void main(String[] args){
new Presentation().generate();
new Business().generate();
new DAO().generate();
}
}
1.2 分析问题
可以看到在上例中,客户端为了使用生成代码的功能,需要与生成多个代码子模块进行交互,耦合度过高。如果其中的子模块变化了,那么客户端生成的代码也需要相应进行变化。
2 带模式的解决方案
2.1 外观模式重写示例
如何理解外观:外观就是从这个组件外部来看有统一的界面,就像是电脑主板的初始化一样,不用管网卡初始化,声卡初始化或者内存初始化,使用者只要知道主板初始化就好,不需要知道初始化的具体细节。
(1)新添加一个Facade对象,用于作为外观模式的界面,代码如下
public class Facade {
public void generate(){
new Presentation().generate();
new Business().generate();
new DAO().generate();
}
}
(2)其他定义和实现都没有变化,包括ConfigModel,ConfigManager,Presentation,Business,DAO
(3)此时的客户端如何实现,直接调用外观对象即可,代码如下:
public class Client {
public static void main(String[] args){
new Facade().generate();
}
}
2.2 外观模式分析
通过上例可以看出,主要变化就是新增了一个外观接口,将客户端的代码搬到了该接口中。
优点有以下几点:
(1)将三个代码生成模块组合成一个整体,方便了客户端的调用,而且封装了系统内部的细节功能
(2)将三个模块封装在一起之后,就如同方法一样,可以实现复用,方便了多个客户端进行调用
(3)对于使用Facade的人员来说,大大降低了学习的难度,就如同电脑主板一样,不需要知道网卡,声卡还有内存如何搭配一样。
3 思考外观模式
3.1 何时选用外观模式
(1)若希望为一个复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式。使用外观对象来实现大部分客户需要的功能,从而简化客户的使用。
(2)构建多层结构的系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样可以简化层间调用,也可以松散层次之间的依赖关系。例如JAVAEE三层架构中,界面层,业务层和数据层之间就可以用此模式,相互之间调用接口,实现隔离。