近日重读《javascript面型对象编程指南》这本书,最后一章介绍了常见的javascript设计模式的实现。主要讲解了四种设计模式:单例模式、工厂模式、装饰器模式和观察者模式。js作为动态语言,实现这四种模式的实例相对简单,当然既然称之为模式,那么吃透思想更重要,那么下面,由乐帝来实例讲解四种模式。
1.单例模式
顾名思义,对象构造出来的是实例,从字面上理解,单例即单实例,这意味一个类只能创建一个实例对象。当需要创建一种类型或者一个类的唯一对象时,可使用该模式。以下两个实例分别从全局变量和类属性两种角度构造单例。属于对象创建型模式。
function Logger(){ if(typeof global_log==="undefined") { global_log=this;//没有在函数内定义global_log所以被看成全局变量,并且此时this为window为全局对象 alert(this);//相当于初始化全局变量并且赋值为window,由于全局变量有唯一性,故可保证单例 } return global_log;//但问题在于全局变量有可能被覆盖掉,造成实例流失 } var a = new Logger(); var b = new Logger(); console.log(a===b);
//另外一种单例模式:构造器属性 function Logger(){//从面向对象的角度考虑,Logger是一个类 if(typeof Logger.single_instance==="undefined"){ Logger.single_instance=this;//Logger.single_instance则是类属性,这个也可以实现单例,类属性和私有属性不同,类属性是类实例公用的 alert(this); } return Logger.single_instance; } var a=new Logger() var b=new Logger() a===b;
2.工厂模式
总的来说,工厂模式属于创建对象型模式,当有多个相似对象不知用哪种,可以考虑工厂模式。也属于创建型模式。
//工厂模式 var MYAPP={}; MYAPP.dom={}; MYAPP.dom.Text=function(){ this.insert=function(where){ var txt=document.createTextNode(this.url); where.appendChild(txt); }; };//有三个相似的对象,三个对象中的方法一样,从而使用也一样 MYAPP.dom.Link=function(){ this.insert=function(where){ var link=document.createElement('a'); link.href=this.url; linlk.appendChild(document.createTextNode(this.url)); where.appendChild(link); }; }; MYAPP.dom.Image=function(){ this.insert=function(where){ var im=document.createElement('img'); im.src=this.url; where.appendChild(im); }; }; /* var o=new MYAPP.dom.Image(); * o.url='www.baidu.com'; * o.insert(document.body); * * var o=new MYAPP.dom.Link(); * o.url='www.baidu.com'; * o.insert(document.body); * * var o=new MYAPP.dom.Text(); * o.url='www.baidu.com'; * o.insert(document.body); */ MYAPP.dom.factory=function(type){ return new MYAPP.dom[type]; }//当构造器过多时,查找不那么一目了然,用工厂函数方法动态操作,省去了如上注释掉的操作或者if操作 var o=MYAPP.dom.factory("Image")//这种方法本质上用到了对象属性的一一对应关系 o.url='www.baidu.com'; o.insert(document.body);
3.装饰器模式
此种模式是一种结构型模式,主要考虑如何拓展对象的功能。可以为一个基础对象创建若干装饰器对象以拓展其功能。由我们的程序自行选择不同装饰器,并使用它们。
var tree={}; tree.decorate=function(){ alert("make sure the tree will not fall"); } tree.getDecorator=function(deco){ tree[deco].prototype=this;//返回新对象并且原tree作为新对象的原型对象 return new tree[deco]; }; tree.RedBalls=function(){//tree的redball属性也是对象 this.decorate=function(){ this.RedBalls.prototype.decorate();//首先调用原型对象decorate方法 alert("put on some red ball"); } }; tree.BlueBalls=function(){ this.decorate=function(){ this.BlueBalls.prototype.decorate();//首先调用原型对象decorate方法 alert("add blue ball"); } }; tree.Angel=function(){ this.decorate=function(){ this.Angel.prototype.decorate();//首先调用原型对象decorate方法 alert("an angel on the top"); } };//以上三个装饰器可按照需要选择 tree=tree.getDecorator("BlueBalls");//返回new tree["BlueBall"],并且保留对tree作为原型对象 tree=tree.getDecorator("RedBalls");//下两个类似 tree=tree.getDecorator("Angel"); tree.decorate();//当调用最后的decorate方法时,会分别上溯调用各自decorate方法中的原型对象方法调用 //装饰器模式的实现,关键在构造新对象时不断保留原对象作为原型对象,同时新对象的方法中,不断调用原型对象的同名方法 //总的来说就是保存原有对象功能的前提下,不断添加新的功能到原有对象
4.观察者模式
此种模式属于行为型模式,主要处理对象之间的交互通信的问题。通常包含两类对象:发行商和订阅商。
//观察者模式 //观察者模式分为推送和拉动两类,推送模式是由发行商负责将消息通知给各个订阅者,以下为推送模式实例 var observer={//观察这对象 addSubscriber:function(callback){ this.subscribers[this.subscribers.length]=callback; },//添加订阅者 removeSubscriber:function(callback){ for(var i=0;i<this.subscribers.length;i++){ if(this.subscribers[i]===callback){ delete(this.subscribers[i]); } } },//移除订阅者 publish:function(what){ for(var i=0; i<this.subscribers.length;i++){ if(typeof this.subscribers[i]==='function'){ this.subscribers[i](what);//广播信息后会传给每个订阅者 } } },//接受并传递数据给订阅者 make:function(o){ for(var i in this){ o[i]=this[i]; o.subscribers=[]; } }//将任意对象转化为发行商,并赋予以上三种方法,即获取添加、移除订阅者功能以及推送消息功能 }; var blogger={ writeBlogPost:function(){ var content='Today is'+new Date(); this.publish(content);//为成为发行商广播信息做准备的步骤 } }; observer.make(blogger);//构造blogger为发行商 var jack={ read:function (what){ console.log('I just read that'+what); } };//准备一个潜在订阅者 blogger.addSubscriber(jack.read);//添加订阅者,注意传送的是函数,这样在订阅者publish函数中就能调用订阅者的函数 blogger.writeBlogPost();//发布信息给订阅者 blogger.removeSubscriber(jack.read);//移除订阅者