参考《javascript设计模式》[美]Addy Osmani一书,下面介绍使用javascript经常会使用的主要设计模式。本博文为ES6语法的博客,还有使用ES5语法的【上】【下】两篇。
主要是以下几个设计模式:
- Constructor Pattern 构造模式
- Module Pattern 模块化模式
- Revealing Module Pattern 揭露模块化模式
- Singleton Pattern 单例模式
- Observer Pattern 观察者模式
- Mediator Pattern 中介者模式
- Prototype Pattern 原型模式
- Command Pattern 命令行模式
- Facade Pattern 外观模式
- Factory Pattern 工厂模式
- Mixin Pattern 混入模式
- Decorator Pattern 装饰者模式
- Flyweight Pattern 享元模式
所有代码挂在我的github上,包含有ES5和ES6语法实现的内容。
https://github.com/zrysmt/javascript-design-pattern
1.Module Pattern 模块化模式
模块化很好理解,目前很多提供模块化的库如require.js(AMD),sea.js(CMD),现在我们就看看怎样自己编写的代码能够支持模块化。
1 | let privateName = Symbol('privateName');//利用Symbol做成私有的变量 |
2.Singleton Pattern 单例模式
确保实例化或者说是创建对象的时候只实例化/创建一次。
- 一般的单例模式
1 | let instance = null; |
- 静态方法和单例模式
静态方法的解释不太容易说清楚,但可以从它的特点和用处来说明:
1)静态方法不会被继承
2)静态方法不用实例化(不用new)能够用直接调用([类名/对象名].[静态方法名])
1 | class mySingleton { |
3.Observer Pattern 观察者模式
观察者一共有四个组件:
- Subject: maintains a list of observers, facilitates adding or removing observers
目标对象(类似接口,不具体实现,只有方法名) - Observer: provides a update interface for objects that need to be notified of a Subject’s changes of state
观察者对象 主要是update方法(类似接口,不具体实现,只有方法名) - ConcreteSubject: broadcasts notifications to observers on changes of state, stores the state of ConcreteObservers
具体目标对象,继承(实现)目标对象(实现接口) - ConcreteObserver: stores a reference to the ConcreteSubject, implements an update interface for the Observer to ensure state is consistent with the Subject’s
具体观察者,继承(实现)观察者(实现接口)
1 | /*Subject 目标*/ |
其实我们现在用的最多的是它的变体-发布-订阅模式
简单解释下该模式,比如我们订阅了某些微信公众号,然后就等着别人发布信息,我们就能立刻接受到信息了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//发布-订阅模式
class Pubsub {
constructor(){
this.subUid = 0; //订阅的id值
this.topics = {};//存放所有订阅者
}
publish(topic, args) {
if (!this.topics[topic]) {
return false;
}
let subscribers = this.topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args);
}
return this;
}
subscribe(topic, func) {
if (!this.topics[topic]) {
this.topics[topic] = [];
}
let token = (++this.subUid).toString();
this.topics[topic].push({
token: token,
func: func
});
return token;
}
unsubscribe(token) {
for (let m in this.topics) {
if (this.topics[m]) {
for (let i = 0, j = this.topics[m].length; i < j; i++) {
if (this.topics[m][i].token === token) {
this.topics[m].splice(i, 1);
return token;
}
}
}
}
return this;
}
}
//usage
let messageLogger = function(topics, data) {
console.log("Logging: " + topics + ": " + data);
};
let pubsub = new Pubsub();
let subscription = pubsub.subscribe("inbox/newMessage", messageLogger);
pubsub.publish("inbox/newMessage", "hello world!");
4.Mediator Pattern 中介者模式
该模式和发布订阅模式非常像,这里就不再重复了
5.Command Pattern 命令行模式
命令行模式就是类似控制台输入命令的方式。说白点就是我们只使用一个方法,第一个参数是我们实际调用的方法,后面的参数是作为该调用方法的参数。
1 | class CarManager { |
6.Facade Pattern 外观模式
外观模式也是只暴露一个很简单的方法,然后该方法在内部执行,调用内部的其他方法,jquery使用了很多这种模式,如$().css、$.ajax()等。
1 | //装饰者模式 |
7.Factory Pattern 工厂模式
怎么解释呢?工厂模式就是创建一个大型的制作工厂,然后其它的对象从这个工厂中产生。
1 | class VehicleFactory { |
8.Mixin Pattern 混入模式
简单解释下,混入就是将一个对象的方法复制给另外一个对象。
1 | //http://es6.ruanyifeng.com/#docs/class#Mixin模式的实现 |
9.Decorator Pattern 装饰者模式
装饰模式是只针对一个基本的对象,添加一些修饰。如下面的是对MacBook,加内存(Memory函数装饰)增加75美元,雕刻(Engraving函数装饰)增加200美元,买保险(Insurance函数装饰)增加250美元。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
36class MacBook {
cost() {
return 997;
}
screenSize() {
return 11.6;
}
}
function Memory(macbook) {
let v = macbook.cost();
macbook.cost = function() {
return v + 75;
};
}
// Decorator 2
function Engraving(macbook) {
let v = macbook.cost();
macbook.cost = function() {
return v + 200;
};
}
// Decorator 3
function Insurance(macbook) {
let v = macbook.cost();
macbook.cost = function() {
return v + 250;
};
}
let mb = new MacBook();
Memory(mb);
Engraving(mb);
Insurance(mb);
console.log(mb.cost());// Outputs: 1522
console.log(mb.screenSize());// Outputs: 11.6
10.Flyweight Pattern 享元模式
享元模式我感觉就是共享一些数据或者方法,有一个工厂可以管理
- Flyweight
享元对象(类似于接口),提供的可以共享的属性/方法; - Concrete Flyweight
具体享元对象,实现接口,具体实现享元对象的方法; - Flyweight Factory
享元工厂对象,创建并管理flyweight对象
实现接口的方法,由于js没有,我们需要模拟。
这部分没有必要完全使用ES6语法,请参考我的上一篇博客。
1 | //在js模拟存虚拟的继承,类似java中的implements |
所有代码挂在我的github上,包含有ES5和ES6语法实现的内容。
https://github.com/zrysmt/javascript-design-pattern