# 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)