0.参考资料
1.概述
- 为子系统中的一组接口提供一个一致(稳定)的界面, Facade模式定义了一个高层接口,这个接口使得这一子系 统更加容易使用(复用)。 —《设计模式》GoF
- 外观模式(Facade),也叫“门面模式:外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端 只需跟这个接口发生调用,而无需关心这个子系统的内部细节
1.1动机
- 组件的客户端和组件中各种复杂的子系统有了
过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦 合面临很多变化的挑战。
1.2结构
- 其中子系统中, 各个组件的依赖由组件自行解决
- 
- 
1.3说明
1. 外观类(Facade): 为调用端提供统一的调用接口, 外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当
子系统对象
1. 调用者(Client): 外观接口的调用者
1. 子系统的集合:指模块或者子系统,处理Facade 对象指派的任务,他是功能的实际提供者
2.要点总结
宏观架构
1. 从客户程序的角度来看,Facade模式简化了整个组件系统的接口
; 对于组件内部与外部客户程序来说,达到了一种”解耦”的效 果 — 内部子系统的任何变化不会影响到Facade接口的变化。
1. Facade设计模式更注重从架构的层次去看整个系统, 而不是单个
类的层次。Facade很多时候更是一种架构设计模式。
1. Facade设计模式并非一个集装箱,可以任意地放进任何多个对象。
Facade模式中组件的内部应该是“相互耦合关系比较大的一系列 组件”, 而不是一个随意的功能集合。
微观代码
1. 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复
杂性
1. 外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展
1. 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
1. 当系统需要进行分层设计时,可以考虑使用Facade模式
1. 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时
可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰简单的接口, 让新系统与Facade类交互,提高复用性
1. 不能过多的或者不合理的使用外观模式,要以让系统有层次,利于维护为目的选择 外观模式/直接调用模块
3.案例
需求
- 组建一个家庭影院:
- DVD播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的
- 功能,其过程为:
- • 直接用遥控器:统筹各设备开关
- • 开爆米花机
- • 放下屏幕
- • 开投影仪
- • 开音响
- • 开DVD,选dvd
- • 去拿爆米花
- • 调暗灯光
- • 播放
- • 观影结束后,关闭各种设备
分析
- 
- 在ClientTest 的main方法中,创建各个子系统的对象,并直接去调用子系统(对象) 相关方法,会造成调用过程混乱,没有清晰的过程
-
不利于在ClientTest 中,去维护对子系统的操作
- **解决思路**:
- 定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比
如在高层接口提供四个方法 ready, play, pause, end ),用来访问子系统中的 一群接口
- 即通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,
使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节 => 外观 模式
4.使用模式
改进引入案例
- 外观模式可以理解为转换一群接口,客户只
要调用一个接口,而不用调用多个接口才能 达到目的。比如:在pc上安装软件的时候经 常有一键安装选项(省去选择安装目录、安 装的组件等等),还有就是手机的重启功能 (把关机和启动合为一个操作)。
-
外观模式就是解决多个复杂接口带来的使用 困难,起到简化用户操作的作用
- 分析:
- 类图: 
新案例
- 模拟去网吧玩电脑和回家
方案
- 使用外观模式,分为 三部分 _(准备 _- _玩电脑 _- _收尾)_
- 每个部分的具体操作则调用具体的子部件组合而成
类图
- 
- 可以看到和客户端Client直接耦合的只有外观类, 而其三大步中的具体实现则有各种组件(互相调用)完成. 组件之间的依赖由组件自身解决.
代码
- 门面类
/**
* @description: 网吧(准备 - 玩电脑 - 收尾)的外观类
* 本案例简单模拟组件之间的依赖: 归属于User的RMB和SFZ
*/
public class InternetFacade {
User user;
WBManager manager;
Computer computer;
{
user = new User("小明");
manager = WBManager.getInstance();
computer = Computer.getInstance();
}
// 玩电脑的准备工作
public void ready(){
user.gotoWb();
manager.showComputer();
manager.register(user);
computer.on();
}
// 玩电脑中
public void play(){
computer.play();
}
// 中途加钱
public void addTime(){
computer.stop();
manager.addTime(user);
}
// 下机走人
public void end(){
computer.shutdown();
manager.getOut(user);
user.backHome();
}
}
- 组件类
@Getter
public class User {
String name;
public User(String name){
this. name = name;
}
private SFZ mySfz = new SFZ();
private RMB myRmb = new RMB();
public void showSfz(){
mySfz.show(name);
}
public void payRMB(){
myRmb.pay(name);
}
public void addRMB(){
myRmb.add(name);
}
public void gotoWb(){
System.out.println("从家到了网吧");
}
public void backHome(){
System.out.println("回到了家");
}
}
// 身份证
public class SFZ {
public void show(String name){
System.out.println("\t" + name + " SFZ: 展示了身份证");
}
}
// 钱
public class RMB {
// 各种行为, 案例中就不具体调用...
public void pay(String name){
System.out.println("\t" + name + " RMB: 付了钱");
}
public void add(String name){
System.out.println("\t" + name + " RMB: 收了钱");
}
}
// 网管
public class WBManager {
private static WBManager instance = new WBManager();
public static WBManager getInstance() {
return instance;
}
public void register(User user) {
System.out.println("前台上号中...(依赖 SFZ类 和 RMB类");
System.out.println("\t展示身份证中...");
user.showSfz();
System.out.println("\t付钱中...");
user.payRMB();
System.out.println("前台上号成功");
}
public void showComputer(){
System.out.println("网管介绍网吧座位分区中");
}
public void addTime(User user) {
System.out.println("前台加钱中...(依赖 SFZ类 和 RMB类");
System.out.println("\t展示身份证中...");
user.showSfz();
System.out.println("\t付钱中...");
user.payRMB();
System.out.println("前台加钱成功");
}
public void getOut(User user) {
System.out.println("下机中...(依赖 SFZ类 和 RMB类");
System.out.println("\t展示身份证中...");
user.showSfz();
System.out.println("\t退钱中...");
user.addRMB();
}
}
// 上的机子
public class Computer {
private static Computer instance = new Computer();
public static Computer getInstance() {
return instance;
}
public void on (){
System.out.println("电脑开机");
}
public void play(){
System.out.println("电脑游戏中");
}
public void stop(){
System.out.println("电脑挂起");
}
public void shutdown(){
System.out.println("电脑关机");
}
}
- 测试
public class Client {
public static void main(String[] args) {
InternetFacade internetFacade = new InternetFacade();
// 玩电脑的前摇
internetFacade.ready();
// 玩电脑中
internetFacade.play();
// 可能的插曲: 余额不足准备加钱
if (true){
internetFacade.addTime();
}
// 后摇
internetFacade.end();
}
}
从家到了网吧
网管介绍网吧座位分区中
前台上号中...(依赖 SFZ类 和 RMB类
展示身份证中...
小明 SFZ: 展示了身份证
付钱中...
小明 RMB: 付了钱
前台上号成功
电脑开机
电脑游戏中
电脑挂起
前台加钱中...(依赖 SFZ类 和 RMB类
展示身份证中...
小明 SFZ: 展示了身份证
付钱中...
小明 RMB: 付了钱
前台加钱成功
电脑关机
下机中...(依赖 SFZ类 和 RMB类
展示身份证中...
小明 SFZ: 展示了身份证
退钱中...
小明 RMB: 收了钱
回到了家
5.经典使用
5.1MyBatis中Configuration.newMetaObject(Object obj) : MetaObject
代码
- 
类图
- 