2019-12-30 | 设计模式 | UNLOCK | 更新时间:2019-12-30 16:34

JS 的设计模式介绍(二)

模块化模式

模块化模式最初被定义为对传统工程中的类提供私有和公共封装的方法,在js中,模块化模式进一步模拟类的概念,通过这一种方法,可以在单一的对象中包含私有/公有的方法和变量。

let testModal=(function(){
  var conunter=0 // 私有变量
  return {
    incem:function(){
      return conunter++
    },
    reset:function(){
      console.log(conunter)
      conunter=0
    }
  }
})()

testModal.incem()
testModal.reset()

Observer 观察者模式

一个被称为被观察者的对象维护一组被称为观察者的对象,这些对象依赖于被观察者被观察者将自身的状态的任何变化都通知观察者,它采取广播的形式,这条广播可能包括特定于这条广播的一些数据,当我们不在希望某个特定的观察者获得通知的时候,我们可以从把它从观察者列表中删除

//观察者列表
function ObserverList(){
	this.observerList=[]
}
ObserverList.prototype.Add=function(obj){ //添加
	return this.observerList.push(obj)
}
ObserverList.prototype.Empty=function(){ //清空
	this.observerList=[]
}
ObserverList.prototype.Count=function(){ //观察者数量
	return this.observerList.length
}
ObserverList.prototype.Get=function(index){//获取其中一个
	if(index>-1&&index<this.observerList.length){
		return this.observerList[index]
	}
}
ObserverList.prototype.Insert=function(obj,index){ //插入其中
	var pointer=-1
	if(index===0){
		this.observerList.unshift(obj) // 插入开头,返回位置
		pointer=index
	}else if(index===this.observerList.length){ //插入结尾
		this.observerList.push(obj)
		pointer=index
	}
	return pointer
}
ObserverList.prototype.IndexOf=function(obj,startIndex){ //查找所在位置
	let i =startIndex,pointer=-1
	while(i<this.observerList.length){
		if(this.observerList[i]===obj){
			pointer=i
		}
		i++
	}
	return pointer
}
ObserverList.prototype.RemoveAt=function(index){ //删除
	if(index===0){
		this.observerList.shift() //删除头部
	}else if(index===this.observerList.length -1){
		this.observerList.pop()
	}
}
//被观察者的原型
function Subject(){
	this.observers=new ObserverList();
}
Subject.prototype.AddObserver=function(observer){ //增加
	this.observers.Add(observer)
}
Subject.prototype.RemoveObserver=function(observer){ //删除
	this.observers.RemoveAt(this.observers.IndexOf(observer,0))
}
Subject.prototype.Notify=function(context){ //通知
	var observerCount=this.observers.Count()
	for(let i=0;i<observerCount;i++){
		this.observers.Get(i).Update(context) //循环执行更新
	}
}
function extend(extension,obj){ //循环将 某身份属性 塞入obj
	for(let key in extension){
		obj[key]=extension[key]
	}
}
function Observer(){
	this.Update=function(text){
		this.checked=text
	}
}
var controlCheckbox=document.getElementById('mainCheckbox'),
	addBth=document.getElementById('addNewObserver'),
	container=document.getElementById('observersContainer')
//创建 具体被观察者
extend(new Subject(),controlCheckbox);
//绑定点击的时候通知 
controlCheckbox['onclick']=new Function('controlCheckbox.Notify(controlCheckbox.checked)')
addBth['onclick']=AddNewObserver
//具体观察者
function AddNewObserver(){
	let check=document.createElement('input')
	check.type='checkbox'
	extend(new Observer(),check)
	check.update=function(value){
		this.checked=value
	}
	controlCheckbox.AddObserver(check) //增加观察者
	container.appendChild(check)
}

发布/订阅模式

发布/订阅模式作为观察者模式的变体,有许多相同的地方也有许多不同的地方,观察者模式要求想要接受通知的观察者需要在被观察者上注册这个事件,发布/订阅模式则使用一个频道,订阅者和发布者通过频道传递特殊的数据

function Public() {
  this.handlers = {};
}
Public.prototype = {
    // 订阅事件
    on: function(eventType, handler){
        var self = this;
        if(!(eventType in self.handlers)) {
           self.handlers[eventType] = [];
        }
        self.handlers[eventType].push(handler);
        return this;
    },
     // 触发事件(发布事件)
    emit: function(eventType){
       var self = this;
       var handlerArgs = Array.prototype.slice.call(arguments,1);
       for(var i = 0; i < self.handlers[eventType].length; i++) {
         self.handlers[eventType][i].apply(self,handlerArgs);
       }
       return self;
    },
    // 删除订阅事件
    off: function(eventType, handler){
        var currentEvent = this.handlers[eventType];
        var len = 0;
        if (currentEvent) {
            len = currentEvent.length;
            for (var i = len - 1; i >= 0; i--){
                if (currentEvent[i] === handler){
                    currentEvent.splice(i, 1);
                }
            }
        }
        return this;
    }
};
var Publisher = new Public();
//订阅事件a
Publisher.on('a', function(data){
    console.log(1 + data);
});
Publisher.on('a', function(data){
    console.log(2 + data);
});
//触发事件a
Publisher.emit('a', '我是第1次调用的参数');
Publisher.emit('a', '我是第2次调用的参数');