javascript设计模式小记

一、单体模式
用于保存一组属性或方法(简单的可以是一个对象字面量),如果可实例化,只能被实例化1次(即return)。

(function(){
...
return {
....
}
})()

可用来划分划分命名空间,封装私有属性和方法(return出来的是公用接口);可实现惰性加载(再一步封装,在使用时才实例化);还可以实现分支技术。

二、工厂模式
在一个方法中,需要用到几个类的实例,而这些类都实现了相同的接口(可能派生自一个类),所以可以互换使用。把创建这些类的实例的代码单拿出来放在一个地方(可以是一个单体或一个新建的类中等),这个地方就是工厂。
工厂可以弱化对象之间的耦合,增强代码的重用性,统一在一个地方,方便维护和管理。

三、桥接模式
将抽象和其实现分离,利于模块坏和单元测试。
比如用在事件监听的回调函数中。

el.addEventListener('click', 'fnA', 'false');
function fnA(){
var id = this.id;
....
}

这种情况fnA与el耦合,方法不能进行单元测试,改用桥接模式:

function fnB(id){
...
}
el.addEventListener('click', 'fnQqiao', 'false');
fnQqiao(){
fnB(this.id);
}

大概这个意思,fnB可以进行单元测试,也可以用在其他地方。

四、组合模式

自由组合,每个叶对象和组合对象都实现了相同的接口,可以互换使用。
只需对顶层操作,所有叶对象都执行方法(组合类中用一个数据结构储存子对象,遍历操作)。如果树的结构庞大,不宜使用。

五、门面模式
简化接口,方便使用。常用到的addEvent,createXHR等方法,还有jq,YUI等JS库都属于门面模式。

六、适配器模式
现有有的接口不能满足要求,又不想完全重写浪费时间,中间加个包装器。

function fnA(str1, str2,str3){
//原方法支持3个字符串参数
}

现有的数据是对象字面量形式的:

var a = {
str1 : '111',
str2 : '222',
str3 : '333'
}

要把对象a传到fnA中就需要用到适配器:

function fnB(o){
fnA(o.str1, o.str2, o.str3);
}

七、装饰者模式
为现有的对象添加新的特性,如果通过添加子类不容易实现(特性有多种组合,需创建大量子类),可使用装饰者模式。装饰者生成的对象和原来的对象使用相同接口,可以直接代替原对象使用。

var jiekou = new Interface('jiekou',['fanA','fanB']);//实现了2个方法的接口
function ClassA(){}
ClassA.prototype = {
fnA : function(){},
fnB : funciton(){}
}

创建装饰者:

function ClassB(obj){
Interface.ensureImplements(obj, jiekou);
this.obj = obj
}
ClassB.prototype = {
fnA : function(){
return this.obj.fnA()+10;
},
funB : function(){
return this.obj.fnB()+5;
}
}
var a = new ClassA();
a = new ClassB(a);

ClassB就是ClassA的装饰者,最后创建的a对象和原a对象方法都是等同的,但值改变了。

八、享元模式
如果一个类会创建很多实例,并且有些数据(this.a,this.b,this.c等)在实例是一样的,其他一些数据(this.d,this.e)在实例中存在差异化,可以把d和e这样的数据拿出来直接传到方法中去,而a,b,c这样的数据是共享的。
然后用一个工厂来创建对象,判断如果对象创建过了,就直接返回对象;否则创建新对象。这样会大大提高内存和CPU使用率。

function ClassA(text){
this.text = text;
this.element = document.createElement('div');
}
ClassA.prototype.set = function(){
this.element.innerHTML = this.text;
}
var a = new ClassA('111');
a.set();
console.log(a.element.innerHTML);

假设页面需要大量的ClassA的对象,就会创建大量div。下面改成享元模式:

var A = (function(){
function ClassA(){
this.element = document.createElement('div');
}
ClassA.prototype.set = function(text){
this.element.innerHTML = text;
}
var objA = null;
return{
createA : function(text){
if(objA == null){
objA = new ClassA();
}
objA.set(text);
return objA;
}
}
})();
var a = A.createA('111');
console.log(a.element.innerHTML);

大概是这个意思,这样不管创建多少对象,就创建了一个DIV。

九、代理模式--虚拟代理
用代理对象代替原来对象进行访问,它们都实现了相同的借口。创建代理对象的实例其实还是间接的创建了原对象,并不是像装饰者那样创建了新的类。
目的是把本体的实例化推迟到真正需要的时候(适合实例化本体比较费时和本体尺寸较大)。也就是说创建一个代理实例,当执行实例方法的时候才真正创建本体的实例。

function ClassA(a){
this.a = a;
}
ClassA.prototype = {
fnA : function(){},
fnB : fucntion(){},
...
}
var a = ClassA('1');//这样会马上实例化ClassA

下面使用代理模式:

function ClassAProxy(a){
this.a = a;
this.obj = null;
}
ClassAProxy.prototype = {
_init : function(){
if(this.obj == null){
this.obj = new ClassA(this.a);
}
},
fnA : function(){
this._init();
return this.obj.fnA();
},
fnB : function(){
this._init();
return this.obj.fnB();
}
}
var a = ClassAProxy('1');//这里并没有实例化ClassA
a.fnA();//当调用方法时候才实例化ClassA。

十、观察者模式
把人行为和应用程序的行为分开。事件监听器(addEventListener)就是一个内置观察者。你可以这样,点击一次执行2个事件:

el.addEventListener('click', fnA, false);
el.addEventListener('click', fnB, false);

但却不能这样:

el.onclick = fnA();
el.onclick = fnB();

十一、命令模式
所有命令对象都执行一个操作(execute),用途就是调用命令对象所绑定的操作(action)。
就是element不和action直接绑定,element执行的是execute,execute在去调用action。而action是灵活的。

var Command = function(action){//命令类
this.action = action;
}
Command.prototype.execute = function(){
this.action();
}
var jiekou = new Interface('jiekou',['execute ']);//创建接口
function ClassMethod(name){//方法类
this.name = name;
}
ClassMethod.prototype = {
consoleMethod : function(){
console.log(this.name);
},
alertMethod : function(){
alert(this.name);
}
}
function fn(command){//执行的地方
Interface.ensureImplements(command, jiekou);
command.execute;
}
var a = new ClassMethod('11');
var consoleCommand = new Command (a.consoleMethod);//创建2个命令
var alertCommand = new Command (a.alertMethod);
fn(consoleCommand);//执行命令
fn(alertCommand);

十二、职责连模式
假如要添加一个对象,要判断对象属于哪个类(假如有5个类),可能生成5个实例来判断。创建一个职责链,每一个接受者对请求分析,要么处理它,要么往下传。

原文地址:https://www.cnblogs.com/bianyuan/p/2356666.html