《Javascript设计模式与开发实践》关于设计模式典型代码的整理:单例模式、策略模式、代理模式、迭代器模式、发布-订阅模式、命令模式、组合模式

1、单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

使用闭包封装私有变量

// 使用闭包创建单例

var user = (function () {

var _name = 'sven',

_age = 29;

return {

getUserInfo: function () {

return _name + '-' + _age;

}

}

})();

惰性单例(只在合适的时候创建对象,并且之创建唯一的一个,试用于dom重复生成、事件绑定等场景)

// 惰性单例生成

var getSingle = function (fn) {

var result;

return function () {

return result || (result = fn.apply(this, arguments));

}

};

2、策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

// 策略模式

var strategies = {

"S": function (salary) {

return salary * 4;

},

"A": function (salary) {

return salary * 3;

},

"B": function (salary) {

return salary * 2;

},

};

var calculateBonus = function (level, salary) {

return strategies[level](salary);

}

// 测试

console.log(calculateBonus('S', 20000));

console.log(calculateBonus('A', 10000));

3、代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。

// 虚拟代理

var myImage = (function () {

var imgNode = document.createElement('img');

document.body.appendChild(imgNode);

return {

setSrc: function (src) {

imgNode.src = src;

}

}

})();

var proxyImage = (function () {

var img = new Image;

img.onload = function () {

myImage.setSrc(this.src);

}

return {

setSrc: function (src) {

myImage.setSrc('file:// /C:/Users/svenzeng/Desktop/loading.gif');

img.src = src;

}

}

})();

// 测试

proxyImage.setSrc('http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

// 缓存代理

var mult = function () {

console.log('开始计算乘积');

var a = 1;

for(var i = 0, l = arguments.length; i < l; i++) {

a = a * arguments[i];

}

return a;

}

var proxyMult = (function () {

var cache = {};

return function () {

var args = Array.prototype.join.call(arguments, ',');

if(args in cache) {

return cache[args];

}

return cache[args] = mult.apply(this, arguments);

}

})();

// 测试

proxyMult(1,2,3,4);

proxyMult(1,2,3,4);

4、迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

// 迭代器模式

var each = function(ary, callback) {

for (var i = 0, l = ary.length; i < l; i++) {

callback.call(ary[i], i, ary[i]);

}

};

// 测试

each([1, 2, 3], function(i, n) {

alert ([i, n]);

});

5、发布-订阅模式:它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知。

// 发布-订阅模式

var event = {

clientList: [],

listen: function (key, fn) {

if (!this.clientList[key]) {

this.clientList[key] = [];

}

this.clientList[key].push(fn); // 订阅的消息添加进缓存列表

},

trigger: function () {

var key = Array.prototype.shift.call(arguments);

fns = this.clientList[key];

if (!fns || fns.length === 0) { // 如果没有绑定对应的消息

return false;

}

for (var i = 0, fn; fn = fns[i++];) {

fn.apply(this, arguments);

}

},

remove: function (key, fn) {

var fns = this.clientList[key];

if (!fns) { // 如果 key 对应的消息没有被人订阅,则直接返回

return false;

}

if (!fn) { // 如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅

fns && (fns.length = 0);

} else {

for (var l = fns.length - 1; l >= 0; l--) {

var _fn = fns[l];

if (_fn ===fn) {

fns.splice(l, 1); // 删除订阅者的回调函数

}

}

}

}

};

// 安装发布—订阅功能

var installEvent = function (obj) {

for (var i in event) {

obj[i] = event[i];

}

};

// 测试

var salesOffices = {};

installEvent( salesOffices );

salesOffices.listen( 'squareMeter88', fn1 = function( price ){

console.log( '价格= ' + price );

}); // 小明订阅消息

salesOffices.listen( 'squareMeter88', fn2 = function( price ){

console.log( '价格= ' + price );

}); // 小红订阅消息

salesOffices.remove( 'squareMeter88', fn1 );

salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000

6、命令模式:用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。

// 命令模式

var bindClick = function (button, func) {

button.onclick = func;

};

var MenuBar = {

refresh: function () {

console.log('刷新菜单界面');

}

};

var SubMenu = {

add: function () {

console.log('增加子菜单');

},

del: function () {

console.log('删除子菜单');

}

};

// 测试

bindClick(button1, MenuBar.refresh);

bindClick(button2, SubMenu.add);

bindClick(button3, SubMenu.del);

7、组合模式:将对象组合成树形结构,以表示“部分-整体”的层次结构。

// 组合模式

var closeDoorCommand = {

execute: function () {

console.log('关门');

}

};

var openPcCommand = {

execute: function () {

console.log('开电脑');

}

};

var openQQCommand = {

execute: function () {

console.log('登录 QQ');

}

};

var MacroCommand = function () {

return {

commandsList: [],

add: function (command) {

this.commandsList.push(command);

},

execute: function () {

for (var i = 0, command; command = this.commandsList[i++];) {

command.execute();

}

}

}

};

// 测试

var macroCommand = MacroCommand();

macroCommand.add(closeDoorCommand);

macroCommand.add(openPcCommand);

macroCommand.add(openQQCommand);

macroCommand.execute();

转自:https://blog.csdn.net/QQsilhonette/article/details/84943932