一. 定义:
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. 如果你希望为一个复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式,使用外观对象来实现大部分客户需要的功能,从而简化客户的使用。