# JavaScript 中的设计模式

# 前言

​ 设计模式,往往是软件设计中的最佳实践,是前人对问题的解决经验的总结。我认为学习并理解设计模式,对自己的程序设计,软件开发有很大帮助,同时也可以扩展自己开发设计的思维。我是后来才明白,所有编程语言,都有设计模式这一说法,读《JavaScript 中的设计模式》这本书,给了我很大启发。

# 关于 ES6 的继承:

​ 子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类没有自己的 this 对象,而是继承父类的 this 对象,然后对其进行加工。如果不调用 super 方法,子类就得不到 this 对象。

ES5 的继承,实质是先创造子类的实例对象 this ,然后再将父类的方法添加到 this 上面( Parent.apply(this) )。

ES6 的继承机制完全不同,实质是先创造父类的实例对象 this (所以必须先调用 super 方法),然后再用子类的构造函数修改 this 。

如果子类没有定义 constructor 方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有 constructor 方法。

1
2
3
4
5
6
7
8
9
class ColorPoint extends Point {
}

// 等同于
class ColorPoint extends Point {
constructor(...args) {
super(...args);
}
}

# 设计模式的六大原则

  • 单一职责原则(Single Responsibility Principle);
  • 开闭原则(Open Closed Principle);
  • 里氏替换原则(Liskov Substitution Principle);
  • 迪米特法则(Law of Demeter),又叫 “最少知道法则”;
  • 接口隔离原则(Interface Segregation Principle);
  • 依赖倒置原则(Dependence Inversion Principle)。
image-20221115144952471

# 创造型设计模式(5)

# 1. 工厂模式

​ 工厂模式是比较常用的设计模式之一,那么什么叫模式呢?简单来说,就是你需要什么东西,不直接使用 new 的方法生成实例,而是通过工厂加工再生成实例。

​ 比如我们现在需要生产三种形状,分别为:圆形,正方形,三角形。我们可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Circle {
draw = () => {
console.log("画了一个圆形");
};
}
class Triangle {
draw = () => {
console.log("画了一个三角形");
};
}
class Square {
draw = () => {
console.log("画了一个正方形");
};
}
const myCircle = new Circle();
myCircle.draw(); //画了一个圆形

​ 但是这样的话,每次我需要一个圆形,都要自己 new 一个 Circle,如果需要其他形状,又要 new 一个其他的构造类,下面我们来建一个工厂,负责生产不同的形状。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class shapeFactory {
getShape(shapeType) {
switch (shapeType) {
case "Circle": {
return new Circle(); //生产new圆
}
case "Triangle": {
return new Triangle();
}
case "Square": {
return new Square();
}
}
}
}
const shapefactory = new shapeFactory();
const myCircle = shapefactory.getShape("Circle");
const myTriangle = shapefactory.getShape("Triangle");
myCircle.draw() //画了一个圆形
myTriangle.draw() //画了一个三角形

工厂模式的优势:使用工厂模式的好处也是显而易见的,比如实例的生产比较复杂,或者说生成实例后还需要额外加工,这个时候工厂给了我们一个统一的出入口,也方便了日后对这个实例的修改。比如你要修改产出是一个单例的时候,就不需要在所有类中修改,而只需要在工厂出口修改即可。

# 2. 抽象工厂模式

​ 抽象工厂?这名字确实挺抽象,因为一般来讲一个工厂只负责加工一个组件,而你的产品需要很多组件合成组装,因此你需要很多生产不同组件的工厂,那么如何管理这些工厂呢,那就用生产工厂的工厂!

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
  //形状有哪些
class Circle {
draw = () => {
console.log("画了一个圆形");
};
}
class Triangle {
draw = () => {
console.log("画了一个三角形");
};
}
class Square {
draw = () => {
console.log("画了一个正方形");
};
}
//颜色有哪些
class Blue {
fill = () => {
console.log("填充蓝色")
}
}
class Red {
fill = () => {
console.log("填充红色")
}
}
class Yellow {
fill = () => {
console.log("填充黄色")
}
}
//先拿到上文的形状工厂
class ShapeFactory {
getShape(shapeType) {
switch (shapeType) {
case "Circle": {
return new Circle();
}
case "Triangle": {
return new Triangle();
}
case "Square": {
return new Square();
}
}
}
}
//再创建一个颜色工厂负责上色
class ColorFactory {
getColor(colorType) {
switch (colorType) {
case 'Blue':{
return new Blue();
}
case 'Green':{
return new Green();
}
case 'Yellow':{
return new Yellow();
}
}
}
}
//抽象工厂,负责管理下面所有工厂
class FatherFactory {
getFactory(choice) {
switch (choice) {
case 'Color':{
return new ColorFactory();
}
case 'Shape':{
return new ShapeFactory();
}
}
}
}
//现在开始生产
const fatherfactory = new FatherFactory()
const colorfactory = fatherfactory.getFactory('Color') //生产颜色工厂
const shapefactory = fatherfactory.getFactory('Shape') //生产形状工厂

const myCircle = shapefactory.getShape('Circle')
myCircle.draw() // "画了一个圆形"
const blue = colorfactory.getColor('Blue')
blue.fill(); // "填充蓝色"

说说好处:和工厂模式类似,抽象工厂模式方便了对各种工厂的管理。

# 3. 单例模式

​ 顾名思义,单例模式就是每个实例只生产一次。单例模式又分为两种,一种叫懒汉式,一种叫饿汉式。区别在于,懒汉式是使用的时候才初始化,饿汉式是先初始化,需要用的时候直接给。
​ 值得注意的是懒汉式写法在 java 中可能会对线程安全有影响,但是 JS 是单线程的,不需要考虑线程安全哈哈哈,所以优先考虑懒汉式。

TODO…

# 结构型设计模式(8)

# 行为型设计模式(12)