0%

20220722

JS 中的设计模式

解决一些特定问题的方法,并总结起来,给一个名字。

定义

在面向对象软件设计过程中针对特定的问题简洁而优雅的解决方案。

原则

找出程序中变化的地方,并将变化封装起来

鸭子类型

如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。

多态

同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈。

1
2
3
4
5
6
7
8
9
10
11
class Duck {}
class Chicken {}
const makeSound = function (animal) {
if (animal instanceof Duck) {
console.log("嘎嘎嘎");
} else if (animal instanceof Chicken) {
console.log("咯咯咯");
}
};
makeSound(new Duck()); // 嘎嘎嘎
makeSound(new Chicken()); // 咯咯咯
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
const makeSound = function (animal: Animal) {
animal.sound();
};
class Animal {
sound() {
throw new Error("不存在sound");
}
}
class Duck extends Animal {
sound() {
console.log("嘎嘎嘎");
}
}
class Chicken extends Animal {
sound() {
console.log("嘎嘎嘎");
}
}
makeSound(new Duck()); // 嘎嘎嘎
makeSound(new Chicken()); // 咯咯咯
// 更多...
// class Chicken extends Animal {
// sound() {
// console.log("嘎嘎嘎");
// }
// }

多态最根本的作用就是通过把过程化的条件分支语句转化为对象的多态性,从而消除这些条件分支语句

封装

考虑你的设计中哪些地方可能变化,这种方式与关注会导致重新设计的原因相反。它不是考虑什么时候会迫使你的设计改变,而是考虑你怎样才能够在不重新设计的情况下进行改变。这里的关键在于封装发生变化的概念,这是许多设计模式的主题

原型模式

基于原型链

单例模式

定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点

场景

  • 需要频繁实例化然后销毁的对象
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象
  • 有状态的工具类对象
  • 繁访问数据库或文件的对象

应用

  • window 对象
  • 日志文件
  • 应用配置
  • 线程池

代理模式

定义

代理模式是为一个对象提供一个代替品或占位符,以便控制对他的访问

场景

  • 明星的经纪人
  • 生产数据库访问
  • 翻墙

迭代器模式

定义

顺序访问一个聚合对象的元素,而不需要暴露对象的内部表示。

基本不需要自己实现,大部分语言内置了迭代器

场景

  • Array.prototype.forEach

发布订阅模式

定义

对象间的一对多的依赖关系,当一个对象的状态发生改变时,所以依赖于他的对象都能接受到通知

场景

  • JS 事件模型

命令模式

定义

命令是对命令的封装,每一个命令都是一个操作,请求方发出请求,接收方接收请求,并执行操作。命令模式解耦了请求方和接收方,命令模式属于行为型模式

场景

  • 处理一些功能,但是不知道请求的接收者是谁,操作是什么,希望以一种松耦合的方式来设计程序。
  • JS 高阶函数

组合模式

定义

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结

场景

  • 树形菜单
  • 文件
  • 文件夹的管理

模板模式

定义

在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

场景

  • 造房子
  • 泡茶还是泡咖啡

策略模式

定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

计算绩效

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
const calculateBonus = function (
performanceLevel: "S" | "A" | "B",
salary: number
) {
if (performanceLevel === "S") {
return salary * 4;
}
if (performanceLevel === "A") {
return salary * 3;
}
if (performanceLevel === "B") {
return salary * 2;
}
};
calculateBonus("B", 20000); // 输出:40000

// ts实现
const bounsMap = new Map([
["S", (salary: number) => salary * 4],
["A", (salary: number) => salary * 3],
["B", (salary: number) => salary * 2],
]);
bounsMap.get("S")?.(1000);

// 完整实现
enum strategyEnum {
S = "S",
A = "A",
B = "B",
}
const bounsMap = new Map<strategyEnum, { times: number }>([
[strategyEnum.S, { times: 4 }],
[strategyEnum.B, { times: 3 }],
[strategyEnum.B, { times: 2 }],
]);

const getBouns = (strategy: strategyEnum, salary: number) => {
const bouns = bounsMap.get(strategy);
if (!bouns) {
return 0;
}
return bouns.times * salary;
};
getBouns(strategyEnum.S, 1000);