大话设计模式十二:外观模式(facade)

一. 定义:

facade模式定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块。这个接口使得客户端调用非常方便。


二. 结构:

大话设计模式十二:外观模式(facade)_第1张图片

三. 序列图:



四. 体会外观模式:

生活中的示例 -- 组装电脑

1. 完全自己组装,什么都得自己搞定

大话设计模式十二:外观模式(facade)_第2张图片

2. 找专业装机公司,不需要自己折腾

大话设计模式十二:外观模式(facade)_第3张图片

五. 模拟实例:

假设客户端现在需要和系统的多个模块进行交互:

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


你可能感兴趣的:(设计模式,外观模式,门面模式)