对几种常见的设计模式的理解 (javascript实现)
设计模式的核心原则:
- 单一职责原则(SRP)
- 一个对象(方法)只做一件事情
- 开放-封闭原则(OCP)
- 软件实体(类、模块、函数)等应该是可以扩展的,但是不可修改。
- 最少知识原则(LKP)
- 一个软件实体应当尽可能少地与其他实体发生相互作用。(调用链不要太长和过于复杂)
- 比如(情景:将军需要让(士兵 function)挖散兵坑)
- (复杂的情况)将军通知上校让他叫来少校,然后让少校找来上尉,并让上尉通知一个军士,最后军士唤来一个士兵,然后将军命令士兵挖掘一些散兵坑。
- (简单情况)将军有个调度部,命令调度部去挖掘一些散兵坑就行了,调度部会安排士兵去
- 一个软件实体应当尽可能少地与其他实体发生相互作用。(调用链不要太长和过于复杂)
几种常见的设计模式:
- 单例模式
- 迭代器模式
- 代理(中介)模式
- 发布-订阅模式
- 装饰器模式
1. 单例模式
定义:确保一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象等
在JavaScript开发中,单例模式的用途非常广泛。试想一下,当我们单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。
单个单例参考:
// 单例构造函数
function CreateSingleton (name) {
this.name = name;
this.getName();
};
// 获取实例的名字
CreateSingleton.prototype.getName = function() {
console.log(this.name)
};
// 单例对象
var Singleton = (function(){ // 用闭包特性,保存唯一的单例
var instance; // 保存唯一的单例
return function (name) {
if(!instance) {
instance = new CreateSingleton(name);
}
return instance;
}
})();
// 创建实例对象1
var a = new Singleton('a');
// 创建实例对象2
var b = new Singleton('b');
console.log(a === b); // true
通用单例参考:
var singleton = function(fn) {
var instance;
return function() {
return instance || (instance = fn.apply(this, arguments));
}
};
// 创建遮罩层
var createMask = function(){
// 创建div元素
var mask = document.createElement('div');
// 设置样式
mask.style = 'xxx'
document.body.appendChild(mask);
// 单击隐藏遮罩层
mask.onclick = function(){
this.style.display = 'none';
}
return mask;
};
// 创建登陆窗口
var createLogin = function() {
// 创建div元素
var login = document.createElement('div');
// 设置样式
login.style = 'xxx'
login.innerHTML = 'login it';
document.body.appendChild(login);
return login;
};
document.getElementById('btn').onclick = function() {
singleton(createMask)();
singleton(createLogin)();
}
总结:需要有一个变量去保存单例
2. 迭代器模式
可以很简便的实现遍历
- js也内置了迭代器(some、every、forEach、map、filter)等
// 手动实现一个迭代器
var each = function(ary, callback){
for (var i = 0, l = ary.length; i < l; i++){
if (callback.call(ary[i], i, ary[i]) === false){ // callback 的执行结果返回false,提前终止迭代
break;
}
}
};
each([1, 2, 3, 4, 5], function(i, n){
if (n > 3){ // n 大于3 的时候终止循环
return false;
}
console.log(n); // 分别输出:1, 2, 3
});
3. 代理(中介)模式
为一个对象提供一个代用品或占位符,以便控制对它的访问
代理模式是一种非常有意义的模式,在生活中可以找到很多代理模式的场景。
- 比如,明星都有经纪人作为代理。如果想请明星来办一场商业演出,只能联系他的经纪人。经纪人会把商业演出的细节和报酬都谈好之后,再把合同交给明星签。
代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理之后,再把请求转交给本体对象
举个实际例子:
- 通过增加虚拟代理的方式,把预加载图片的职责放到代理对象中,而本体仅仅负责往页面中添加img标签,这也是它最原始的职责。
此例子是:我们需要加载一个大图,大图比较慢,在大图未加载好之前,先用菊花图loading.gif替代
// myImage负责往页面中添加img标签:
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ) {
imgNode.src = src;
}
}
})();
// proxyImage负责预加载图片,并在预加载完成之后把请求交给本体myImage:
var proxyImage = (function() {
var img = new Image;
img.onload = function() {
myImage.setSrc( this.src );
}
return {
setSrc: function( src ) {
myImage.setSrc( './loading.gif' );
img.src = src;
}
}
})();
proxyImage.setSrc( 'http://imgcache.qq.com/music/photo/xxxxxxbig.png' );
4. 发布-订阅模式(观察者模式)
博主姊妹篇:发布-订阅模式详解(观察者模式)
5. 装饰器模式
其他伙伴写的:https://segmentfault.com/a/1190000013664124
个人整理,有误可留言。
部分参考丛书 《JavaScript设计模式与开发实践》曾探