外观模式概念及其解释

外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。

它为子系统提供了一个接口,屏蔽一个或多个子系统的复杂功,提供了一个一致的界面(接口)给用户。外观模式是一个非常简单的模式,但它的功能却很强大,非常有用。外观模式不仅简化类中的接口,而且对接口与调用者也进行了解耦。外观模式可以将一些复杂操作封装起来,并创建一个简单的接囗用于调用,它经常出现在多层架构的系统中。

使用场景

  • 子系统复杂 : 子系统复杂 , 通过使用外观模式可以简化调用接口。

    子系统通常会随着时间的推进变得越来越复杂。 即便是应用了设计模式, 通常你也会创建更多的类。 尽管在多种情形中子系统可能是更灵活或易于复用的, 但其所需的配置和样板代码数量将会增长得更快。 为了解决这个问题, 外观将会提供指向子系统中最常用功能的快捷方式, 能够满足客户端的大部分需求。

  • 层次复杂 : 系统结构层次复杂 , 每个层级都一个使用外观对象作为该层入口 , 可以简化层次间的调用接口。

外观模式优缺点

优点

  • 简化调用: 简化复杂系统的调用过程, 无需对子系统进行深入了解, 即可完成调用。

  • 降低耦合: 使用外观模式, 只与外观对象进行交互, 不与复杂的子系统直接进行交互, 降低了系统间的依赖, 使耦合关系更低; 子系统内部的模块更容易扩展和维护。

  • 符合最少知道原则

缺点

  • 子系统扩展风险: 系统内部扩展子系统时, 容易产生风险。

  • 不符合开闭原则: 如果系统设计不当,增加新的子系统可能需要修改外观类的源代码。

外观模式相关角色

  1. 外观:

    1. 知道哪些子系统负责处理请求。
    2. 将客户的请求委托给相应的子系统对象。
  2. 子系统:

    1. 实现和执行专门的子系统功能。
    2. 对门面一无所知,也没有参照物。
  3. 客户端: 负责通过外观类调用子系统的功能

注: 有些文章中会提到附加外观角色,它主要是对外观的辅助,避免多种不相关的功能污染单一外观。

外观模式的实际应用

不同浏览器点击事件兼容处理

1
2
3
<div id="kinghiee" 
style="width: 200px;height: 60px;background:blue;margin: auto;"
></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 获取container的DOM元素
let container = document.querySelector('#kinghiee');

// 使用外观模式
function addEvent(dom, type, fn) {
if(dom.addEventListener) {
// 如果支持DOM2级事件addEventListener
dom.addEventListener(type, fn, false); // 子系统
} else if(dom.attachEvent) {
// IE9以下的浏览器
dom.attachEvent('on'+type, fn); // 子系统
} else {
// 如果以上两种均不支持
dom['on'+type] = fn; // 子系统
}
}

// 客户端
addEvent(container, 'click', function() {
console.log('点击事件兼容性处理');
});

兼容不同浏览器冒泡行为

1
2
3
4
5
6
7
8
9
let eventBubble = function(event) {
if(event.stopPropagation) {
// 标准浏览器
event.stopPropagation();
} else {
// IE浏览器
event.cancelBubble = true;
}
}

模拟电脑启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 子系统
function CPU() {
this.startup = function () {
console.log("启动CPU");
};
}

// 子系统
function Memory() {
this.startup = function () {
console.log("启动Memory");
};
}

// 子系统
function Disk() {
this.startup = function () {
console.log("启动Disk");
};
}

// 外观
function Computer() {
let _cpu, _memory, _disk; // 定义计算机内部系统变量
_cpu = new CPU();
_memory = new Memory();
_disk = new Disk();

this.start = function () {
_cpu.startup();
_memory.startup();
_disk.startup();
}
}

// 客户端调用
computer = new Computer();
computer.start();

外观模式应用于很多地方,例如平时使用jquery的ajax函数(内部对不同浏览器类型XML请求对象的创建)、parent()、find() 等