一. 定义:
facade模式定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块。这个接口使得客户端调用非常方便。
二. 结构:
三. 序列图:
四. 体会外观模式:
生活中的示例 -- 组装电脑
1. 完全自己组装,什么都得自己搞定
2. 找专业装机公司,不需要自己折腾
五. 模拟实例:
假设客户端现在需要和系统的多个模块进行交互:
1. A模块的接口:
public interface AModuleApi { public void testA(); }2. A模块的实现:
public class AModuleImpl implements AModuleApi{ public void testA() { System.out.println("现在在A模块里面操作testA方法"); } }3. B模块的接口:
public interface BModuleApi { public void testB(); }4. B模块的实现:
public class BModuleImpl implements BModuleApi{ public void testB() { System.out.println("现在在B模块里面操作testB方法"); } }5. C模块的接口:
public interface CModuleApi { public void testC(); }6. C模块的实现:
public class CModuleImpl implements CModuleApi{ public void testC() { System.out.println("现在在C模块里面操作testC方法"); } }7. 外观类:
public class Facade { /** * 示意方法,满足客户需要的功能 */ public void test(){ //在内部实现的时候,可能会调用到内部的多个模块 AModuleApi a = new AModuleImpl(); a.testA(); BModuleApi b = new BModuleImpl(); b.testB(); CModuleApi c = new CModuleImpl(); c.testC(); } }8. 不用facade,需要用户自己和多个模块交互:
public class Client { public static void main(String[] args) { // 不用Facade,需要自己跟多个模块交互 AModuleApi a = new AModuleImpl(); a.testA(); BModuleApi b = new BModuleImpl(); b.testB(); CModuleApi c = new CModuleImpl(); c.testC(); } }9. 使用facade,调用就一行代码,简化了操作
public class Client { public static void main(String[] args) { //使用了Facade new Facade().test(); } }
六. 一个真实的例子:
代码生成系统,使用外观模式,用户可以一键生成表现层、业务层、dao层的代码,而无需知道对应的业务。
此例子使用了多种设计模式:简单工厂、单例、外观模式等。
1. 代码生成系统的外观接口
public interface FacadeApi { public void generate(); }2. 代码生成系统的外观实现
public class Facade implements FacadeApi { /** * 客户端需要的,一个简单的调用代码生成的功能 */ public void generate() { new Presentation().generate(); new Business().generate(); new DAO().generate(); } }3. 工厂,用于生成外观对象
public class FacadeFactory { private FacadeFactory() { } public static FacadeApi createFacadeApi() { return new Facade(); } }4.描述配置的Bean
public class ConfigModel { // 是否需要生成表现层,默认是true private boolean needGenPresentation = true; // 是否需要生成逻辑层,默认是true private boolean needGenBusiness = true; // 是否需要生成DAO,默认是true private boolean needGenDAO = true; public boolean isNeedGenPresentation() { return needGenPresentation; } public void setNeedGenPresentation(boolean needGenPresentation) { this.needGenPresentation = needGenPresentation; } public boolean isNeedGenBusiness() { return needGenBusiness; } public void setNeedGenBusiness(boolean needGenBusiness) { this.needGenBusiness = needGenBusiness; } public boolean isNeedGenDAO() { return needGenDAO; } public void setNeedGenDAO(boolean needGenDAO) { this.needGenDAO = needGenDAO; } }5. 配置管理,就是负责读取配置文件,并把配置文件的内容设置到配置bean中去,是一个单例
public class ConfigManager { private static ConfigManager manager = null; private static ConfigModel model = null; private ConfigManager() { } public static ConfigManager getInstance() { if (manager == null) { manager = new ConfigManager(); model = new ConfigModel(); // 读取配置文件,把值设置到ConfigModel中去 } return manager; } /** * 获取配置的数据 * @return 配置的数据 */ public ConfigModel getConfigData() { return model; } }6. 生成表现层的模块
public class Presentation { public void generate() { // 1:从配置管理里面获取相应的配置信息 ConfigModel cm = ConfigManager.getInstance().getConfigData(); if (cm.isNeedGenPresentation()) { // 2:按照要求去生成相应的代码,并保存成文件 System.out.println("正在生成表现层代码文件"); } } }7. 生成业务层的模块
public class Business { public void generate() { // 1:从配置管理里面获取相应的配置信息 ConfigModel cm = ConfigManager.getInstance().getConfigData(); if (cm.isNeedGenBusiness()) { // 2:按照要求去生成相应的代码,并保存成文件 System.out.println("正在生成逻辑层代码文件"); } } }8. 生成数据层的模块
public class DAO { public DAO() { } public void generate() { // 1:从配置管理里面获取相应的配置信息 ConfigModel model = ConfigManager.getInstance().getConfigData(); if (model.isNeedGenDAO()) { // 2:按照要求去生成相应的代码,并保存成文件 System.out.println("正在生成数据层代码文件"); } } }9. 客户端调用很简单
public class Client { public static void main(String[] args) { FacadeApi api = FacadeFactory.createFacadeApi(); api.generate(); } }
七. 理解外观模式:
使用外观模式不是给系统添加新的功能接口,而是为了让外部减少系统内多个模块的交互,松散耦合,从而让外部能够更简单的使用子系统。
八. 何时使用外观模式:
1. 如果你希望为一个复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式,使用外观对象来实现大部分客户需要的功能,从而简化客户的使用。