概念

外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂系统提供一个简单的接口

它通过隐藏系统的复杂性,为客户端提供一个简单的接口,使得客户端与系统的子系统之间的通信和交互更加简单


在外观模式中,一个单一的外观类提供了一个高级接口,它将系统中的一组接口进行了封装,对外只暴露少量的接口,客户端通过这些接口与系统进行交互,而不需要了解系统中具体的子系统之间的关联和细节


举个例子,考虑一个电脑系统,它包含了各种硬件和软件组件,如CPU、内存、硬盘、操作系统等

客户端如果要使用这些组件,可能需要直接与这些组件进行交互,这样会使得客户端代码变得复杂且不易维护

使用外观模式,可以定义一个电脑外观类,封装各个组件的初始化、启动和关闭等操作,客户端只需要与电脑外观类交互,而不需要了解具体的硬件和软件组件


实现条件

  1. 系统包含多个子系统

    系统由多个复杂的子系统组成,这些子系统可能相互关联,但客户端不需要知道这些细节

  2. 需要简化客户端与子系统之间的交互

    客户端需要与系统交互,但由于系统复杂性的原因,直接与子系统交互可能会导致代码复杂性增加

  3. 需要实现系统的解耦

    客户端与系统之间的耦合度过高,需要通过一个统一的接口来降低耦合度,从而实现系统的解耦

  4. 需要提供统一的接口

    系统中的一组接口需要被封装在一个统一的接口后面,以简化客户端的操作

  5. 需要提高系统的安全性和稳定性

    通过外观模式,可以对系统进行更好的封装和隔离,提高系统的安全性和稳定性


优点

  1. 简化接口

    外观模式提供了一个简单的接口,隐藏了系统的复杂性,使得客户端只需与外观类交互,而不需要了解系统的内部结构和细节

  2. 降低耦合度

    外观模式降低了客户端与系统之间的耦合度,客户端只与外观类进行交互,而不需要直接与系统中的各个子系统交互,从而降低了代码的复杂度

  3. 提高可维护性

    外观模式将系统中的复杂性封装在一个外观类中,使得系统更易于理解、维护和修改

  4. 提高安全性和稳定性

    通过外观模式,可以对系统进行更好的封装和隔离,提高了系统的安全性和稳定性

  5. 遵循单一职责原则

    外观模式将系统中的各个子系统功能进行了分离,每个子系统只负责自己的功能,遵循了单一职责原则


缺点

  1. 不符合开闭原则

    如果需要新增或修改系统的功能,可能需要修改外观类,这违反了开闭原则

  2. 可能隐藏系统的复杂性过多

    外观模式可能会导致系统的某些复杂性被过度隐藏,使得一些高级功能无法实现,或者导致性能问题

  3. 可能引入性能损耗

    在某些情况下,外观模式可能会引入额外的性能损耗,因为客户端通过外观类来访问子系统,而不是直接访问,可能会增加额外的调用开销


实现方式

定义子系统,跟外观系统

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
* 音频解码器类 (Class)
*
* 负责解码音频文件。
*/
class AudioDecoder {
/**
* 解码指定的音频文件。
* @param {string} audioFile 需要解码的音频文件路径或名称。
*/
decode(audioFile) {
console.log(`解码音频文件: ${audioFile}`)
}
}

/**
* 音频控制器类 (Class)
*
* 负责管理音频的播放控制。
*/
class AudioController {
/**
* 播放音频。
*/
play() {
console.log("播放音频")
}

/**
* 暂停音频。
*/
pause() {
console.log("暂停音频")
}

/**
* 停止音频播放。
*/
stop() {
console.log("停止音频")
}
}

/**
* 音量控制器类 (Class)
*
* 负责管理音量的设置。
*/
class VolumeController {
/**
* 设置音量级别。
* @param {number} volumeLevel 需要设置的音量级别。
*/
setVolume(volumeLevel) {
console.log(`设置音量为: ${volumeLevel}`)
}
}

/**
* 音频播放器外观类 (Class)
*
* 提供一个简单统一的接口来控制音频的播放、暂停、停止以及音量设置,隐藏了子系统的复杂性。
* 通过封装`AudioDecoder`、`AudioController`和`VolumeController`等子系统,简化了对外部使用者的交互逻辑。
*/
class AudioPlayerFacade {
/**
* 构造函数,初始化音频解码器、音频控制器和音量控制器。
*/
constructor() {
this.audioDecoder = new AudioDecoder()
this.audioController = new AudioController()
this.volumeController = new VolumeController()
}

/**
* 播放指定的音频文件。
* @param {string} audioFile 需要播放的音频文件路径或名称。
*/
playAudio(audioFile) {
this.audioDecoder.decode(audioFile)
this.audioController.play()
}

/**
* 暂停当前正在播放的音频。
*/
pauseAudio() {
this.audioController.pause()
}

/**
* 停止当前正在播放的音频。
*/
stopAudio() {
this.audioController.stop()
}

/**
* 设置播放音量。
* @param {number} volumeLevel 需要设置的音量级别。
*/
setVolume(volumeLevel) {
this.volumeController.setVolume(volumeLevel)
}
}


export default AudioPlayerFacade

怎么使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 使用外观模式控制音频播放
// 导入AudioPlayerFacade类
import AudioPlayerFacade from '../AppearancePattern'

// 创建一个AudioPlayerFacade的实例
const audioPlayerFacade = new AudioPlayerFacade()

// 播放音频文件"music.mp3"
audioPlayerFacade.playAudio("music.mp3")

// 暂停当前正在播放的音频
audioPlayerFacade.pauseAudio()

// 设置音量为80%
audioPlayerFacade.setVolume(80)

// 停止当前正在播放的音频
audioPlayerFacade.stopAudio()


场景

  1. jQuery

    jQuery 是一个流行的 JavaScript 库,它简化了 DOM 操作和事件处理

    通过使用 jQuery,开发人员可以使用简洁的语法来访问和操作 DOM 元素,从而隐藏了底层浏览器的差异性,这可以看作是一种外观模式的应用

  2. React

    React 是一个用于构建用户界面的 JavaScript 库,它采用了组件化的开发模式

    在 React 中,每个组件都可以看作是一个外观,它封装了一部分 UI 和逻辑,并提供了一个简单的接口供其他组件使用

  3. Vue.js

    Vue.js 是另一个流行的 JavaScript 框架,也是基于组件化开发的

    在 Vue.js 中,组件提供了一个简单的接口来封装复杂的 UI 和逻辑,从而降低了组件之间的耦合度,这也可以看作是一种外观模式的应用

  4. Bootstrap:

    Bootstrap 是一个流行的前端框架,它提供了许多预定义的 UI 组件和样式,可以帮助开发人员快速构建具有统一外观和响应式设计的网站和应用程序


源代码