设计模式
设计模式就是一些长期软件工程实践中积累下来经验,遵守这些模式代码会变得更加可复用可维护可扩展,前端设计模式规则,开放封闭(对扩展开放,对内部修改封闭)以及单一职责(一个函数只做一件事),总的来说就是变和不变进行分离,确保变化的部分灵活、不变的部分稳定。
- 工厂模式:
把不变的部分封装起来(工厂),只需要我们通过传递变的参数(原料)进去来生产想要的东西,是变和不变分离原则的一种体现。
js
// 汽车工厂示例
class Car {
constructor(type) {
this.type = type;
}
}
class CarFactory {
create(type) {
switch(type) {
case 'SUV':
return new Car('SUV');
case 'Sedan':
return new Car('Sedan');
}
}
}
const factory = new CarFactory();
const suv = factory.create('SUV');
const sedan = factory.create('Sedan');
console.log(suv.type); // "SUV"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 单例模式:
确保只有一个实例
ES6 的模块其实就是单例模式,模块中导出的对象就是单例的,多次导入其实是同一个引用。
js
class Singleton {
static instance;
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const s1 = new Singleton();
const s2 = new Singleton();
console.log(s1 === s2); // true
//es6
// module.js
let instance;
export default { name: 'Singleton' };
// main.js
import singleton1 from './module.js';
import singleton2 from './module.js';
console.log(singleton1 === singleton2); // 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 策略模式:
算法的使用和算法的实现分离开来,一般用来消除过多的 if else,同时代码复用性扩展性也提高
js
// 奖金计算策略(根据不同绩效执行不同算法)
const strategies = {
'S': salary => salary * 4,
'A': salary => salary * 3,
'B': salary => salary * 2,
};
class BonusCalculator {
constructor(strategy) {
this.strategy = strategy;
}
calculate(salary) {
return strategies[this.strategy](salary);
}
}
const bonus = new BonusCalculator('S').calculate(10000);
console.log(bonus); // 40000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 发布订阅者模式:
发布者维护一份存有订阅者信息的列表,当满足某个触发条件时,就会通知列表里的所有订阅者
比如事件流里面的监听函数(订阅者),当事件触发时去通知所有监听这个事件的监听函数
- 跨组件通信
在 Vue/React 中作为事件总线,替代深层嵌套的props
传递。 - 异步操作解耦
例如上传完成后触发多个回调(日志、UI 更新、缓存清理)。 - 插件系统扩展
通过事件机制让第三方插件监听核心模块的关键行为(如路由变化、数据提交)。
js
class EventEmitter {
constructor() {
this.handlers = {};
}
//订阅事件
on(eventName, cb) {
this.handlers[eventName] ? this.handlers[eventName].push(cb) : (this.handlers[eventName] = [cb]);
}
//取消订阅
off(eventName, cb) {
this.handlers[eventName] = this.handlers[eventName].filter(callBack => callBack !== cb);
}
//发布事件
emit(eventName, ...args) {
// 避免在回调函数中修改原数组,故需要复制一份
this.handlers[eventName] ? this.handlers[eventName].slice().forEach(cb => cb(...args)) : null;
}
//只订阅一次
once(eventName, cb) {
const wrapper = (...args) => {
cb(...args);
this.off(eventName, wrapper);
// console.log('11off');
};
this.on(eventName, wrapper);
// console.log('11on');
}
}
// 测试
const emitter = new EventEmitter();
const callback = message => console.log(message);
emitter.on('greet', callback);
emitter.emit('greet', 'Hello, World!'); // 应该输出: Hello, World!
emitter.once('greetOnce', callback);
emitter.emit('greetOnce', 'Hello for the first time!'); // 应该输出: Hello for the first time!
emitter.emit('greetOnce', 'Hello for the second time!'); // 不应该有输出
emitter.off('greet', callback);
emitter.emit('greet', 'Hello again!'); // 不应该有输出
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
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
- 观察者模式:
定义了一对多的依赖关系,当一个对象状态改变时,所有依赖他的对象都要得到通知并更新
js
// 被观察者
class Observerd {
constructor() {
this.observerList = [];
}
// 添加观察者
addObserver(Observer) {
this.observerList.push(Observer);
}
// 移除观察者
removeObserver(Observer) {
this.observerList = this.observerList.filter(item => item !== Observer);
}
// 通知观察者
notify() {
this.observerList.forEach(Observer => Observer.update());
}
}
class Observer {
constructor(doSomo) {
this.doSomo = doSomo;
}
update() {
console.log(this.doSomo);
}
}
const ob1 = new Observer('我是ob1');
const ob2 = new Observer('我是ob2');
const ob3 = new Observer('我是ob3');
const test = new Observerd();
test.addObserver(ob1);
test.addObserver(ob2);
test.addObserver(ob3);
test.removeObserver(ob2);
test.notify();
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
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