设计模式
大约 3 分钟
设计模式
单例模式
- 定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点
- 实现:用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象
var Singleton = function (name) {
this.name = name
}
Singleton.prototype.getName = function () {
alert(this.name)
}
Singleton.getInstance = (function (name) {
var instance = null
return function (name) {
if (!instance) {
instance = new Singleton(name)
}
return instance
}
})()
var a = Singleton.getInstance('sven1')
var b = Singleton.getInstance('sven2') // 已存在instance,直接返回sven1
alert(a === b) // true
- 惰性单例模式,在调用时创建实例
var getSingle = function (fn) {
var result
return function () {
return result || (result = fn.apply(this, arguments)) // 如果存在实例,直接返回
}
}
// 点击按钮,出现弹窗,重复点击,支出现一次
var createLoginLayer = function () {
var div = document.createElement('div')
div.innerHTML = '我是登录浮窗'
div.style.display = 'none'
document.body.appendChild(div)
return div
}
var createSingleLoginLayer = getSingle(createLoginLayer)
document.getElementById('loginBtn').onclick = function () {
var loginLayer = createSingleLoginLayer()
loginLayer.style.display = 'block'
}
发布-订阅模式(观察者模式)
对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知
eg:售楼信息
var salesOffices = {} // 定义售楼处 salesOffices.clientList = {} // 缓存列表,存放订阅者的回调函数 salesOffices.listen = function (key, fn) { if (!this.clientList[key]) { this.clientList[key] = [] // 如果还没有订阅过此类消息,给该类消息创建一个缓存列表 } this.clientList[key].push(fn) // 订阅的消息添加进消息缓存列表 } salesOffices.trigger = function () { // 发布消息 var key = Array.prototype.shift.call(arguments) // 取出消息类型 var fns = this.clientList[key] // 取出该消息对应的回调函数集合 if (!fns || fns.length === 0) { // 如果没有订阅该消息,则返回 return false } for (var i = 0, fn; (fn = fns[i++]); ) { fn.apply(this, arguments) // (2) // arguments 是发布消息时附送的参数 } } salesOffices.listen('squareMeter88', function (price) { // 小明订阅 88 平方米房子的消息 console.log('价格= ' + price) // 输出: 2000000 }) salesOffices.listen('squareMeter110', function (price) { // 小红订阅 110 平方米房子的消息 console.log('价格= ' + price) // 输出: 3000000 }) salesOffices.trigger('squareMeter88', 2000000) // 发布 88 平方米房子的价格 salesOffices.trigger('squareMeter110', 3000000) // 发布 110 平方米房子的价格
通用的发布订阅模式,全局 Event
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 ) // (1); var fns = this.clientList[ key ]; if ( !fns || fns.length === 0 ){ // 如果没有绑定对应的消息 return false; } for( var i = 0, fn; fn = fns[ i++ ]; ){ fn.apply( this, arguments ); // (2) // arguments 是 trigger 时带上的参数 } }, 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( 'squareMeter100', fn2 = function( price ){ // 小红订阅消息 console.log( '价格= ' + price ); }); //salesOffices.remove( 'squareMeter88', fn1 ); // 删除小明的订阅 salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000 salesOffices.trigger( 'squareMeter100', 3000000 ); // 输出:3000000