参考《javascript设计模式》[美]Addy Osmani一书,下面介绍使用javascript经常会使用的主要设计模式。本博文是使用ES5语法的【上】篇,还有一个【下】篇,ES6语法会单独写个博客。
主要是以下几个设计模式:
- 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.1 对象字面量表示法
1 | var myModule = { |
1.2 Module(模块)模式
- 私有–IIFE模拟
1 | var testModule = (function() { |
- Module(模块)模式变化–混入
1 | var myModule = (function(jQ, _) { |
- Module(模块)模式变化–引出
1
2
3
4
5
6
7
8
9
10
11
12
13
14var myModule = (function() {
// Module object
var module = {},
privateVariable = "Hello World";
function privateMethod() {
// ...
}
module.publicProperty = "Foobar";
module.publicMethod = function() {
console.log(privateVariable);
};
return module;
}());
2.Revealing Module Pattern 揭露模块化模式
其实简单说就是将要暴露的接口返回(return)出去1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23var myRevealingModule = function() {
var privateVar = "Ben Cherry",
publicVar = "Hey there!";
function privateFunction() {
console.log("Name:" + privateVar);
}
function publicSetName(strName) {
privateVar = strName;
}
function publicGetName() {
privateFunction();
}
return {
setName: publicSetName,
greeting: publicVar,
getName: publicGetName
};
}();
myRevealingModule.setName("Paul Kinlan");
3.Singleton Pattern 单例模式
确保实例化或者说是创建对象的时候只实例化/创建一次。
1 | var mySingleton = (function() { |
- 静态方法
静态方法的解释不太容易说清楚,但可以从它的特点和用处来说明:
1)静态方法不会被继承
2)静态方法不用实例化(不用new)能够用直接调用([类名/对象名].[静态方法名])
ES6在方法前加上static
关键字即可,使用ES6实现的见另外一篇博客,或者直接在github中查看我的源代码。使用ES5语法实现见下面:
1 | var SingletonTester = (function() { |
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
具体观察者,继承(实现)观察者(实现接口)
具体观察者模式的代码请移步到我的github中,这里就不单独列出来了。
其实我们现在用的最多的是它的变体-发布-订阅模式
简单解释下该模式,比如我们订阅了某些微信公众号,然后就等着别人发布信息,我们就能立刻接受到信息了。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
61var pubsub = {};
(function(q) {
var topics = {},//存放所有订阅者
subUid = -1;
//发布
q.publish = function(topic, args) {
if (!topics[topic]) {
return false;
}
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args);
}
return this;
};
//订阅
q.subscribe = function(topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
});
return token;
};
//取消订阅
q.unsubscribe = function(token) {
for (var m in topics) {
if (topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return this;
};
}(pubsub));
//测试
var messageLogger = function(topics, data) {
console.log("Logging: " + topics + ": " + data);
};
var subscription = pubsub.subscribe("inbox/newMessage", messageLogger);
pubsub.publish("inbox/newMessage", "hello world!");
// or
pubsub.publish("inbox/newMessage", ["test", "a", "b", "c"]);
// or
pubsub.publish("inbox/newMessage", {
sender: "hello@google.com",
body: "Hey again!"
});
4.Mediator Pattern 中介者模式
该模式和发布订阅模式非常像,这里就不再重复了。
5.Command Pattern 命令行模式
命令行模式就是类似控制台输入命令的方式。说白点就是我们只使用一个方法,第一个参数是我们实际调用的方法,后面的参数是作为该调用方法的参数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20(function() {
var CarManager = {
requestInfo: function(model, id) {
return "The information for " + model + " with ID " + id + " is foobar";
},
buyVehicle: function(model, id) {
return "You have successfully purchased Item " + id + ", a " + model;
},
arrangeViewing: function(model, id) {
return "You have successfully booked a viewing of " + model + " ( " + id + ") ";
}
};
CarManager.execute = function(name) {
return CarManager[name] && CarManager[name].apply(CarManager, [].slice.call(arguments, 1));
};
console.log(CarManager.execute("arrangeViewing", "Ferrari", "14523"));
console.log(CarManager.execute("requestInfo", "Ford Mondeo", "54323"));
console.log(CarManager.execute("buyVehicle", "Ford Escort", "34232"));
})();
所有代码挂在我的github上,包含有ES5和ES6语法实现的内容。
https://github.com/zrysmt/javascript-design-pattern