设计模式

目前我们常说的设计模式,来源于 Erich Gamma、 Richard Helm、 Ralph Johnson 和 John Vlissides(Gang of Four) 编著的《设计模式:可复用面向对象软件的基础》,该书提出了23种软件设计模式(Design Pattern),作为面向对象软件设计的最佳实践,广为人知。

23种设计模式如下:

创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”

– 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。

结构型模式:用于描述如何将类或对象按某种布局组成更大的结构

– 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责

– 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

面向对象设计原则

在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据一些原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。

原则 定义 提出者 目的
开闭原则 软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification) 勃兰特·梅耶(Bertrand Meyer) 降低维护带来的新风险
里氏替换原则 继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects) 里斯科夫(Liskov) 防止继承泛滥
依赖倒置原则 高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions) 罗伯特·马丁(Robert C.Martin) 更利于代码结构的升级扩展
单一职责原则 单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分(There should never be more than one reason for a class to change) 罗伯特·C.马丁(Robert C. Martin) 便于理解,提高代码的可读性
接口隔离原则 一个类对另一个类的依赖应该建立在最小的接口上(The dependency of one class to another one should depend on the smallest possible interface) 罗伯特·C.马丁(Robert C. Martin) 功能解耦,高聚合、低耦合
迪米特法则(最少知道原则) 只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers) 伊恩·荷兰(Ian Holland) 减少代码臃肿

单例模式

单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。

单例模式有 3 个特点:

  • 单例类只有一个实例对象;
  • 该单例对象必须由单例类自行创建;
  • 单例类对外提供一个访问该单例的全局访问点。
1
2
3
4
5
6
7
8
function Singleton() {}
Singleton.getInstance = function() {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
};
// let singleton = Singleton.getInstance();
1
2
3
4
5
6
7
8
9
10
11
function Singleton() {}
Singleton.getInstance = (function() {
let instance = null;
return function () {
if (!instance) {
instance = new Singleton();
}
return instance;
};
})();
// let singleton = Singleton.getInstance();
1
2
3
4
5
6
7
8
9
10
let Singleton = (function() {
let instance = null;
return function() {
if (!instance) {
instance = this;
}
return instance;
}
})();
// let singleton = new Singleton();
Singleton.js
1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}

const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2); // true

原型模式

原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。

1
2
3
function Prototype() {}
let instance = Object.create(Prototype);
// Object.getPrototypeOf(instance);
1
2
3
4
function Prototype() {}
let instance = {};
Object.setPrototypeOf(instance, Prototype);
// Object.getPrototypeOf(instance);
1
2
3
4
5
6
function Prototype() {}
function Instance() {}
Instance.prototype = Prototype;
Instance.prototype.constructor = Instance;
let instance = new Instance();
// Object.getPrototypeOf(instance);
Prototype.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 定义一个原型对象
const prototype = {
name: 'default name',
sayHello() {
console.log(`Hello, my name is ${this.name}`);
},
};

// 创建一个新对象,使用原型作为模板
const obj1 = Object.create(prototype);
obj1.name = 'John';
obj1.sayHello(); // 输出 "Hello, my name is John"

// 创建另一个新对象,使用同样的原型
const obj2 = Object.create(prototype);
obj2.sayHello(); // 输出 "Hello, my name is default name"

工厂模式

工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。

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
function Instance1() {}
function Instance2() {}
function Instance1Factory() {
this.create = function() {
return new Instance1();
}
}
function Instance2Factory() {
this.create = function() {
return new Instance2();
}
}
function InstanceFactory(type) {
this.create = function() {
let factory = null;
switch(type) {
case 1:
factory = new Instance1Factory();
break;
case 2:
factory = new Instance2Factory();
break;
}
factory.create();
}
}
// let instance1Factory = new InstanceFactory(1);
// let instance1 = instance1Factory.create();
Factory.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Car {
constructor(model, year, color) {
this.model = model;
this.year = year;
this.color = color;
}
}

class CarFactory {
createCar(model, year, color) {
return new Car(model, year, color);
}
}

const carFactory = new CarFactory();

const myCar = carFactory.createCar('Tesla', 2021, 'red');
console.log(myCar); // Car { model: 'Tesla', year: 2021, color: 'red' }

抽象工厂模式

抽象工厂(Abstract Factory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。

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
function Instance1() {}
function Instance2() {}
function Instance1Factory() {
this.create = function() {
return new Instance1();
}
}
function Instance2Factory() {
this.create = function() {
return new Instance2();
}
}
function InstanceFactory() {
this.create = function(type) {
switch(type) {
case 1:
return new Instance1Factory().create();
break;
case 2:
return new Instance2Factory().create();
break;
}
}
}
// let factory = new InstanceFactory();
// let instance1 = factory.create(1);
AbstractFactory.js
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
// 抽象工厂模式
class AbstractFactory {
createProductA() {}
createProductB() {}
}

// 具体工厂1
class ConcreteFactory1 extends AbstractFactory {
createProductA() {
return new ProductA1();
}
createProductB() {
return new ProductB1();
}
}

// 具体工厂2
class ConcreteFactory2 extends AbstractFactory {
createProductA() {
return new ProductA2();
}
createProductB() {
return new ProductB2();
}
}

// 抽象产品A
class AbstractProductA {
constructor() {
if (new.target === AbstractProductA) {
throw new Error('抽象类不能实例化');
}
}
methodA() {}
}

// 具体产品A1
class ProductA1 extends AbstractProductA {
methodA() {
console.log('ProductA1 的方法被调用!');
}
}

// 具体产品A2
class ProductA2 extends AbstractProductA {
methodA() {
console.log('ProductA2 的方法被调用!');
}
}

// 抽象产品B
class AbstractProductB {
constructor() {
if (new.target === AbstractProductB) {
throw new Error('抽象类不能实例化');
}
}
methodB() {}
}

// 具体产品B1
class ProductB1 extends AbstractProductB {
methodB() {
console.log('ProductB1 的方法被调用!');
}
}

// 具体产品B2
class ProductB2 extends AbstractProductB {
methodB() {
console.log('ProductB2 的方法被调用!');
}
}

// 客户端
class Client {
constructor(factory) {
const productA = factory.createProductA();
const productB = factory.createProductB();
productA.methodA();
productB.methodB();
}
}

// 使用
const client1 = new Client(new ConcreteFactory1());
const client2 = new Client(new ConcreteFactory2());

建造者模式

建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

Builder.js
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
class Burger {
constructor(builder) {
this.size = builder.size;
this.cheese = builder.cheese || false;
this.pepperoni = builder.pepperoni || false;
this.lettuce = builder.lettuce || false;
this.tomato = builder.tomato || false;
}
}

class BurgerBuilder {
constructor(size) {
this.size = size;
}

addPepperoni() {
this.pepperoni = true;
return this;
}

addLettuce() {
this.lettuce = true;
return this;
}

addCheese() {
this.cheese = true;
return this;
}

addTomato() {
this.tomato = true;
return this;
}

build() {
return new Burger(this);
}
}

const burger = new BurgerBuilder(14)
.addPepperoni()
.addLettuce()
.addTomato()
.build();

console.log(burger); // Burger { size: 14, cheese: false, pepperoni: true, lettuce: true, tomato: true }

代理模式

代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Instance() {
this.method = function() {}
}
function InstanceProxy() {
// proxy could do some extra things
this.instance = new Instance();
// proxy could do some extra things

this.method = function() {
// proxy could do some extra things
this.instance.method();
// proxy could do some extra things
}
}
// let proxy = new InstanceProxy();
// let result = proxy.method();
Proxy.js
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
class RealSubject {
request() {
console.log('RealSubject: Handling request.');
}
}

class ProxySubject {
constructor(realSubject) {
this.realSubject = realSubject;
}

request() {
if (this.checkAccess()) {
this.realSubject.request();
this.logAccess();
}
}

checkAccess() {
console.log('ProxySubject: Checking access prior to firing a real request.');
return true;
}

logAccess() {
console.log('ProxySubject: Logging the time of request.');
}
}

function clientCode(subject) {
subject.request();
}

console.log('Client: Executing the client code with a real subject:');
const realSubject = new RealSubject();
clientCode(realSubject);

console.log('');

console.log('Client: Executing the same client code with a proxy:');
const proxy = new ProxySubject(realSubject);
clientCode(proxy);

适配器模式

适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Instance1() {
this.method1 = function() {}
}
function Instance2() {
this.method2 = function() {}
}
function InstanceAdapter(type) {
this.instance = new type();
this.adapterMethod = function() {
(this.instance.method1 ? this.instance.method1 : this.instance.method2)(...arguments);
}
}
// let adapter1 = new InstanceAdapter(Instance1);
// let adapter2 = new InstanceAdapter(Instance2);
// let result1 = adapter1.adaperMethod();
// let result2 = adapter2.adaperMethod();
Adapter.js
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
// 定义一个旧的接口
class OldInterface {
request() {
return "Old interface is called";
}
}

// 定义一个新的接口
class NewInterface {
specificRequest() {
return "New interface is called";
}
}

// 定义一个适配器,将旧的接口转换为新的接口
class Adapter {
constructor() {
this.oldInterface = new OldInterface();
}

request() {
return this.oldInterface.request().replace("Old", "New");
}
}

// 使用适配器调用新的接口
const adapter = new Adapter();
console.log(adapter.request()); // 输出 "New interface is called"

桥接模式

桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

Bridge.js
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
// 实现者
class Color {
constructor() {
if (new.target === Color) {
throw new Error('Color 不能被初始化。');
}
}

setColor() {
throw new Error('setColor 必须被实现。');
}
}

// 具体实现者
class RedColor extends Color {
constructor() {
super();
}

setColor() {
return '红色';
}
}

class BlueColor extends Color {
constructor() {
super();
}

setColor() {
return '蓝色';
}
}

// 抽象
class Shape {
constructor(color) {
if (new.target === Shape) {
throw new Error('Shape 不能被初始化。');
}

this.color = color;
}

setColor() {
return this.color.setColor();
}

draw() {
throw new Error('draw 必须被实现。');
}
}

// 具体抽象
class Circle extends Shape {
constructor(color) {
super(color);
}

draw() {
return `用 ${this.setColor()} 颜色画一个圆。`;
}
}

class Square extends Shape {
constructor(color) {
super(color);
}

draw() {
return `用 ${this.setColor()} 颜色画一个正方形。`;
}
}

// 使用
const redCircle = new Circle(new RedColor());
console.log(redCircle.draw()); // 输出:用 红色 颜色画一个圆。

const blueSquare = new Square(new BlueColor());
console.log(blueSquare.draw()); // 输出:用 蓝色 颜色画一个正方形。

装饰模式

装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Instance() {}
Instance.prototype.method = function() {
console.log('method1');
}
function Decorator(instance) {
this.instance = instance;
}
Decorator.prototype.method = function() {
this.instance.method();
console.log('method2');
}
var instance = new Instance();
var instanceDecorated = new Decorator(instance);

// instance.method();
// instanceDecorated.method();
使用 @decorator 语法
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
interface TypedPropertyDescriptor<T> {
enumerable?: boolean;
configurable?: boolean;
writable?: boolean;
value?: T;
get?: () => T;
set?: (value: T) => void;
}
function decorator(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor<T>) : TypedPropertyDescriptor<T> | void {
var fn = descriptor.value;
descriptor.value = function(...args: any[]) {
try {
return fn.apply(this, args);
} finally {
console.log('method2');
}
}
return descriptor;
}

class Instance {
@decorator
method() {
console.log('method1');
}
}

// var instance = new Instance();
// instance.method();
Decorator.js
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
// 定义一个基础组件
class Coffee {
cost() {
return 10;
}
}

// 定义一个装饰器
class Milk {
constructor(coffee) {
this.coffee = coffee;
}

cost() {
return this.coffee.cost() + 2;
}
}

// 定义另一个装饰器
class Sugar {
constructor(coffee) {
this.coffee = coffee;
}

cost() {
return this.coffee.cost() + 1;
}
}

// 使用装饰器
let coffee = new Coffee();
coffee = new Milk(coffee);
coffee = new Sugar(coffee);
console.log(coffee.cost()); // 输出 13

外观模式

外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。

1
2
3
4
5
6
7
8
9
function method1() {}
function method2() {}
function method3() {}
function facadeMethod() {
method1();
method2();
method3();
}
// facadeMethod();
Facade.js
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
// 外观模式
class Bank {
constructor(name) {
this.name = name;
}
openAccount() {
console.log(`在${this.name}开户`);
}
}
class Credit {
constructor(name) {
this.name = name;
}
applyForCredit() {
console.log(`在${this.name}申请信用卡`);
}
}
class Facade {
constructor(name) {
this.bank = new Bank(name);
this.credit = new Credit(name);
}
openAccount() {
this.bank.openAccount();
}
applyForCredit() {
this.credit.applyForCredit();
}
}
const facade = new Facade('中国工商银行');
facade.openAccount();
facade.applyForCredit();

享元模式

享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。

Flyweight.js
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
// 享元工厂
class FlyweightFactory {
constructor() {
this.flyweights = {};
}

getFlyweight(key) {
if (this.flyweights[key]) {
return this.flyweights[key];
} else {
const flyweight = new ConcreteFlyweight(key);
this.flyweights[key] = flyweight;
return flyweight;
}
}
}

// 抽象享元
class Flyweight {
constructor() {
if (new.target === Flyweight) {
throw new Error('Flyweight is an abstract class');
}
}

operation() {
throw new Error('operation() must be implemented');
}
}

// 具体享元
class ConcreteFlyweight extends Flyweight {
constructor(key) {
super();
this.key = key;
}

operation() {
console.log(`ConcreteFlyweight with key ${this.key} is being used`);
}
}

// 客户端
class Client {
constructor() {
this.flyweightFactory = new FlyweightFactory();
}

run() {
const flyweight1 = this.flyweightFactory.getFlyweight('key1');
flyweight1.operation();

const flyweight2 = this.flyweightFactory.getFlyweight('key2');
flyweight2.operation();

const flyweight3 = this.flyweightFactory.getFlyweight('key1');
flyweight3.operation();
}
}

const client = new Client();
client.run();

组合模式

组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

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
function Composite(name) {
this.name = name;
this.parent = null;
this.children = [];
}
Composite.prototype = {
add: function(child) {
child.parent = this;
this.children.push(child);
return this;
},
action: function() {
if (this.children.length > 0) {
for (var i = 0; i < this.children.length; ++i) {
this.children[i].action();
}
} else {
console.log(this.name);
// do something
}
}
}
var root = new Composite('root');
var leaf1 = new Composite('leaf1');
var leaf2 = new Composite('leaf2');
var leaf3 = new Composite('leaf3');
var leaf4 = new Composite('leaf4');
var leaf5 = new Composite('leaf5');
var leaf6 = new Composite('leaf6');
var leaf7 = new Composite('leaf7');
root.add(leaf1).add(leaf2).add(leaf3).add(leaf4);
leaf3.add(leaf5).add(leaf6).add(leaf7);

// root.action();
Composite.js
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
// 组合模式
class Component {
constructor(name) {
this.name = name;
this.children = [];
}

add(component) {
this.children.push(component);
}

remove(component) {
const index = this.children.indexOf(component);
if (index !== -1) {
this.children.splice(index, 1);
}
}

display(depth) {
console.log("-".repeat(depth) + this.name);
this.children.forEach((child) => {
child.display(depth + 2);
});
}
}

const root = new Component("root");
root.add(new Component("leaf A"));
root.add(new Component("leaf B"));

const comp = new Component("Composite X");
comp.add(new Component("leaf XA"));
comp.add(new Component("leaf XB"));

root.add(comp);

const comp2 = new Component("Composite XY");
comp2.add(new Component("leaf XYA"));
comp2.add(new Component("leaf XYB"));

comp.add(comp2);

root.add(new Component("leaf C"));

root.display(1);

模版方法模式

模板方法(Template Method)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

TemplateMethod.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class AbstractClass {
templateMethod() {
this.primitiveOperation1();
this.primitiveOperation2();
}
}

class ConcreteClass extends AbstractClass {
primitiveOperation1() {
console.log('具体类实现方法1');
}
primitiveOperation2() {
console.log('具体类实现方法2');
}
}

const concreteClass = new ConcreteClass();
concreteClass.templateMethod();

策略模式

策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var strategy1 = function(val) {
return val * 1
}

var strategy1 = function(val) {
return val * 2
}

var strategy1 = function (val) {
return val * 3
}

var executor = function(fn, val) {
return fn(val);
}

// var params = {}; // strategy parameters
// executor(strategy1, params);
// executor(strategy2, params);
// executor(strategy3, params);
Strategy.js
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
class Context {
constructor(strategy) {
this.strategy = strategy;
}

executeStrategy(num1, num2) {
return this.strategy.doOperation(num1, num2);
}
}

class OperationAdd {
doOperation(num1, num2) {
return num1 + num2;
}
}

class OperationSubtract {
doOperation(num1, num2) {
return num1 - num2;
}
}

class OperationMultiply {
doOperation(num1, num2) {
return num1 * num2;
}
}

const context = new Context(new OperationAdd());
console.log(`10 + 5 = ${context.executeStrategy(10, 5)}`);

context.strategy = new OperationSubtract();
console.log(`10 - 5 = ${context.executeStrategy(10, 5)}`);

context.strategy = new OperationMultiply();
console.log(`10 * 5 = ${context.executeStrategy(10, 5)}`);

命令模式

命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

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
function Command() {
// 命令栈
this.stack = [];
// 栈指针位置
this.stackPosition = -1;
}
Command.prototype = {
// 执行
execute: function(fn) {
this._clearRedo();
var command = fn.bind(this);

// 执行并缓存起来
command();

this.stack.push(command);
this.stackPosition++;
},
canUndo: function() {
return this.stackPosition >= 0;
},
canRedo: function() {
return this.stackPosition < this.stack.length - 1;
},
// 撤销
undo: function(undoFn) {
if (!this.canUndo()) {
return;
}

this.stackPosition--;

// 命令的撤销,与执行的处理相反
undoFn && undoFn.call(this);
},
// 重做
redo: function() {
if (!this.canRedo()) {
return;
}

// 执行栈顶的命令
this.stack[++this.stackPosition]();
},
// 在执行时,已经撤销的部分不能再重做
_clearRedo: function() {
this.stack = this.stack.slice(0, this.stackPosition + 1);
}
}
// var commandar = new Command();
// commandar.execute(function step1(){console.log('command1')});
// commandar.execute(function step2(){console.log('command2')});
// commandar.undo(function undoStep2(){console.log('command3')});
// commandar.redo();
Command.js
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
// 定义命令接口
class Command {
execute() {}
}

// 定义具体命令类
class LightOnCommand extends Command {
constructor(light) {
super();
this.light = light;
}

execute() {
this.light.on();
}
}

// 定义接收者类
class Light {
on() {
console.log('Light is on');
}

off() {
console.log('Light is off');
}
}

// 定义调用者类
class RemoteControl {
constructor() {
this.commands = [];
}

setCommand(command) {
this.commands.push(command);
}

pressButton() {
this.commands.forEach((command) => {
command.execute();
});
}
}

// 创建接收者对象
const light = new Light();

// 创建具体命令对象
const lightOnCommand = new LightOnCommand(light);

// 创建调用者对象
const remoteControl = new RemoteControl();

// 设置命令
remoteControl.setCommand(lightOnCommand);

// 执行命令
remoteControl.pressButton();

职责链模式

职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。

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
function ChainItem(fn) {
this.fn = fn;
this.next = null;
}
ChainItem.prototype = {

setNext: function(next) {
this.next = next;
return next;
},

start: function() {
this.fn.apply(this, arguments);
},

toNext: function() {
if (this.next) {
this.start.apply(this.next, arguments);
} else {
console.log('There is no more chain.');
}
}
};
function action1(input) {
if (/* match action conditions */) {
// do action
}
this.toNext(input);
}
function action2(input) {
if (/* match action conditions */) {
// do action
}
this.toNext(input);
}
function action3(input) {
if (/* match action conditions */) {
// do action
}
this.toNext(input);
}
var chain = new ChainItem(action1);
var action2ChainItem = new ChainItem(action2);
var action3ChainItem = new ChainItem(action3);
chain.setNext(action2ChainItem).setNext(action3ChainItem);

// chain.start();
ResponsibilityChain.js
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
// 定义处理器
class Handler {
constructor() {
this.nextHandler = null;
}

setNextHandler(handler) {
this.nextHandler = handler;
return handler;
}

handleRequest(request) {
if (this.nextHandler !== null) {
return this.nextHandler.handleRequest(request);
}
return null;
}
}

// 定义具体处理器
class ConcreteHandler1 extends Handler {
handleRequest(request) {
if (request === 'request1') {
return 'ConcreteHandler1 handled the request';
}
return super.handleRequest(request);
}
}

class ConcreteHandler2 extends Handler {
handleRequest(request) {
if (request === 'request2') {
return 'ConcreteHandler2 handled the request';
}
return super.handleRequest(request);
}
}

class ConcreteHandler3 extends Handler {
handleRequest(request) {
if (request === 'request3') {
return 'ConcreteHandler3 handled the request';
}
return super.handleRequest(request);
}
}

// 客户端代码
const handler1 = new ConcreteHandler1();
const handler2 = new ConcreteHandler2();
const handler3 = new ConcreteHandler3();

handler1.setNextHandler(handler2).setNextHandler(handler3);

console.log(handler1.handleRequest('request1')); // ConcreteHandler1 handled the request
console.log(handler1.handleRequest('request2')); // ConcreteHandler2 handled the request
console.log(handler1.handleRequest('request3')); // ConcreteHandler3 handled the request
console.log(handler1.handleRequest('request4')); // null

状态模式

状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。

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
function Instance() {
Object.defineProperty(this, 'state', {
set: function(value) {
this._state = value;
let statusActionFunc = this['_' + value + 'Action'];
statusActionFunc && statusActionFunc.call(this);
},
get: function() {
return this._state;
},
enumerable: false
});
this.init();
}
Instance.prototype.init = function() {
this.state = 'status1';
}
Instance.prototype.changeState = function() {
this.state = this.state == 'status1' ? 'status2' : 'status1';
}
Instance.prototype._status1Action = function () {
console.log(this._state);
}
Instance.prototype._status2Action = function () {
console.log(this._state);
}
// var instance = new Instance();
// instance.changeState();
// instance.changeState();
State.js
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
// 定义状态类
class State {
constructor(color) {
this.color = color;
}
handle(context) {
console.log(`turn to ${this.color} light`);
context.setState(this);
}
}

// 定义Context类
class Context {
constructor() {
this.state = null;
}
getState() {
return this.state;
}
setState(state) {
this.state = state;
}
}

// 测试代码
let context = new Context();

let green = new State('green');
let yellow = new State('yellow');
let red = new State('red');

// 绿灯亮了
green.handle(context);
console.log(context.getState());

// 黄灯亮了
yellow.handle(context);
console.log(context.getState());

// 红灯亮了
red.handle(context);
console.log(context.getState());

观察者模式

观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。

Observer.js
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
// 定义主题对象
class Subject {
constructor() {
this.observers = [];
}

// 添加观察者
addObserver(observer) {
this.observers.push(observer);
}

// 删除观察者
removeObserver(observer) {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}

// 通知所有观察者
notifyObservers() {
this.observers.forEach((observer) => {
observer.update();
});
}
}

// 定义观察者对象
class Observer {
constructor(name) {
this.name = name;
}

// 观察者更新方法
update() {
console.log(`${this.name} 收到通知并进行了更新`);
}
}

// 创建主题对象
const subject = new Subject();

// 创建观察者对象
const observer1 = new Observer('观察者1');
const observer2 = new Observer('观察者2');
const observer3 = new Observer('观察者3');

// 添加观察者
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.addObserver(observer3);

// 通知所有观察者
subject.notifyObservers();

// 删除观察者
subject.removeObserver(observer2);

// 通知所有观察者
subject.notifyObservers();

发布订阅模式

发布订阅(Publish-Subscribe)模式:发布订阅模式定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function Observer() {
this.eventTypeObj = {};
}
Observer.prototype.on = function(eventType, fn) {
if (!this.eventTypeObj[eventType]) {
// 按照不同的订阅事件类型,存储不同的订阅回调
this.eventTypeObj[eventType] = [];
}
this.eventTypeObj[eventType].push(fn);
}
Observer.prototype.emit = function() {
// 可以理解为arguments借用shift方法
var eventType = Array.prototype.shift.call(arguments);
var eventList = this.eventTypeObj[eventType];
for (var i = 0; i < eventList.length; i++) {
eventList[i].apply(eventList[i], arguments);
}
}

// var observer = new Observer();
// observer.on('event', function(params) {
// // handle function
// };
// observer.emit('event', {/* params */});
PublishSubscribe.js
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
class PubSub {
constructor() {
this.events = {};
}

subscribe(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}

publish(event, data) {
if (!this.events[event]) {
return;
}
this.events[event].forEach(callback => callback(data));
}
}

const pubsub = new PubSub();

pubsub.subscribe('example', data => {
console.log(`Received data: ${data}`);
});

pubsub.publish('example', 'hello world');

### 观察者模式和发布订阅模式有什么区别

观察者模式和发布订阅模式都是用于解决对象之间的通信问题,但是它们的实现方式有所不同。

观察者模式中,主题对象维护了一个观察者列表,当主题对象发生变化时,会通知所有的观察者进行更新。观察者模式中,观察者和主题对象之间是直接关联的,观察者可以直接访问主题对象。

发布订阅模式中,发布者和订阅者之间通过一个消息队列进行通信。发布者将消息发布到消息队列中,订阅者从消息队列中订阅消息。发布者和订阅者之间是通过消息队列进行解耦的,它们不需要直接关联。

在实际应用中,观察者模式更加简单直接,适用于一对多的通信场景;而发布订阅模式更加灵活,适用于多对多的通信场景。

中介者模式

中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var instance1 = {
value: 1,
rank: rankMediator
}
var instance2 = {
value: 2,
rank: rankMediator
}
var instance3 = {
value: 3,
rank: rankMediator
}
function rankMediator() {
var ranks = [instance1.value, instance2.value, instance3.value].sort(function(a, b) {
return a - b;
});
return ranks.indexOf(this.value) + 1;
}

// instance1.rank(); // 1
// instance1.value = 100;
// isntance1.rank(); // 3
Mediator.js
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
// 中介者模式
class Mediator {
constructor() {
this.colleagues = [];
}

addColleague(colleague) {
this.colleagues.push(colleague);
}

broadcast(sender, message) {
this.colleagues.forEach((colleague) => {
if (colleague !== sender) {
colleague.receive(message);
}
});
}
}

class Colleague {
constructor(mediator) {
this.mediator = mediator;
}

send(message) {
this.mediator.broadcast(this, message);
}

receive(message) {
console.log(`Received message: ${message}`);
}
}

const mediator = new Mediator();

const colleague1 = new Colleague(mediator);
const colleague2 = new Colleague(mediator);
const colleague3 = new Colleague(mediator);

mediator.addColleague(colleague1);
mediator.addColleague(colleague2);
mediator.addColleague(colleague3);

colleague1.send("Hello, World!");
colleague2.send("How are you?");
colleague3.send("Nice to meet you!");

迭代器模式

迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

JavaScript中的有序数据集合有 Array,Map,Set,String,typeArray,arguments,NodeList

以上有序数据集合都部署了 Symbol.iterator 属性,属性值为一个函数,执行这个函数,返回一个迭代器,迭代器部署了 next 方法,调用迭代器的 next 方法可以按顺序访问子元素。同时,任何部署了 Symbol.iterator 接口的数据都可以使用 for…of 循环遍历

1
2
3
4
5
6
7
8
9
10
11
12
var arr = [1, 2, 3, 4];
var iterator = arr[Symbol.iterator]();

console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: 4, done: false}
console.log(iterator.next()); // {value: undefined, done: true}

for (item of arr) {
console.log(item);
}
Iterator.js
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
// 定义一个迭代器
class Iterator {
constructor(list) {
this.list = list;
this.index = 0;
}

next() {
if (this.hasNext()) {
return this.list[this.index++];
}
return null;
}

hasNext() {
return this.index < this.list.length;
}
}

// 定义一个列表
class List {
constructor() {
this.list = [];
}

add(item) {
this.list.push(item);
}

// 获取迭代器
getIterator() {
return new Iterator(this.list);
}
}

// 使用迭代器遍历列表
const list = new List();
list.add('a');
list.add('b');
list.add('c');

const iterator = list.getIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}

访问者模式

访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

Visitor.js
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
// 定义访问者
class Visitor {
visit(element) {
element.accept(this);
}
}

// 定义元素
class Element {
accept(visitor) {
visitor.visit(this);
}
}

// 定义具体元素
class ConcreteElement extends Element {
doSomething() {
console.log('ConcreteElement doSomething');
}
}

// 定义具体访问者
class ConcreteVisitor extends Visitor {
visit(element) {
element.doSomething();
}
}

// 使用
const visitor = new ConcreteVisitor();
const element = new ConcreteElement();
visitor.visit(element);

备忘录模式

备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。

Memento.js
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
// 发起人
class Calculator {
constructor() {
this.currentValue = 0;
}

add(value) {
this.currentValue += value;
}

subtract(value) {
this.currentValue -= value;
}

getCurrentValue() {
return this.currentValue;
}

save() {
return new Memento(this.currentValue);
}

restore(memento) {
this.currentValue = memento.getCurrentValue();
}
}

// 备忘录
class Memento {
constructor(currentValue) {
this.currentValue = currentValue;
}

getCurrentValue() {
return this.currentValue;
}
}

// 管理者
class History {
constructor() {
this.mementos = [];
}

push(memento) {
this.mementos.push(memento);
}

pop() {
return this.mementos.pop();
}
}

const calculator = new Calculator();
const history = new History();

// 添加一些数字
calculator.add(5);
history.push(calculator.save());

calculator.add(10);
history.push(calculator.save());

calculator.subtract(3);
// 输出:保存和添加之前的当前值:15
console.log(calculator.getCurrentValue());

// 弹出两次
calculator.restore(history.pop());
calculator.restore(history.pop());
// 输出:恢复到先前状态后的当前值:5
console.log(calculator.getCurrentValue());

解释器模式

解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

Interpreter.js
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
// 定义表达式类
class Expression {
interpret(context) {
throw new Error('This method should be overwritten!');
}
}

// 定义数字表达式类
class NumberExpression extends Expression {
constructor(number) {
super();
this.number = number;
}

interpret(context) {
return this.number;
}
}

// 定义加法表达式类
class AddExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}

interpret(context) {
return this.left.interpret(context) + this.right.interpret(context);
}
}

// 定义减法表达式类
class SubtractExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}

interpret(context) {
return this.left.interpret(context) - this.right.interpret(context);
}
}

// 定义上下文类
class Context {
constructor() {
this.expression = null;
}

setExpression(expression) {
this.expression = expression;
}

evaluate() {
return this.expression.interpret(this);
}
}

// 使用例子
const context = new Context();
const a = new NumberExpression(10);
const b = new NumberExpression(5);
const c = new NumberExpression(2);
const d = new AddExpression(a, b);
const e = new SubtractExpression(d, c);

context.setExpression(e);
console.log(context.evaluate()); // 输出 13