模式有三种:Architectural Pattern、Design Pattern、Coding Pattern,即:框架模式、设计模式、编程模式。本文主要讲解Javascript中的设计模式,好的设计模式能够提高代码的重用性,可读性,使代码更容易的维护和扩展。本文适合有一点javascript基础,对javascript的概念有所了解。
单例模式是javascript中最常用的模式,它是将自己的代码放在一个命名空间下,这样的好处是可以减少使用全局变量,在多人协同开发时也能避免命名冲突等问题。这样的好处是维护起来非常方便,如下例:
1 var m = {2 name: 'dog',3 action: function() {4 console.log(this.name);5 }6 };7 m.action();//调用
或者
1 var dog = function() {2 this.name = 'dog';3 this.action = function() {4 return console.log(this.name);5 };6 action();7 };8 dog(); //调用
工厂模式就是将对象的方法创建交给外部对象,这样的好处就是解决了对象之间的相互影响、即耦合,避免了使用new来实例化对象,有助于创建模块化的代码,维护起来也方便。工厂模式分为简单工厂模式和抽象工厂模式,下面介绍简单工厂模式:
1 var m = {};2 m.action = function() {3 console.log('dog');4 };5 var demo = function() {6 m.action();7 };8 demo()//调用
抽象工厂模式先设计一个抽象类,这个类不能被实例化,只能用来派生子类,最后通过对子类的扩展实现工厂方法。如下:
1 var f = function() {}; 2 f.PRototype = { 3 c: function() { 4 throw new Error('can/'t use this method');//如果调用此方法会报错,因为它是用来派生子类不能实例化 5 } 6 }; 7 var e = function() { 8 f.call(this); 9 }10 e.prototype = new f();11 e.prototype.constructor = e;12 e.prototype.c = function() {13 console.log('this method is redefine');14 }15 // 调用16 var demo = new e();17 demo.c();
桥接模式是将抽象与实现隔离,一遍二者独立变化。在设计一个javascript API的时候,它可以用来弱化类和对象之间的耦合。它还可以用来把多个类联接在一起。例如:
1 var class1 = function(a,b,c) { 2 this.a = a; 3 this.b = b; 4 this.c = c; 5 }; 6 var class2 = function(d) { 7 this.d = d; 8 }; 9 var demo = function(a,b,c,d) {10 this.one = new Class1(a,b,c);11 this.two = new Class2(d);12 };
组合模式可以用一条命令在多个对象上激发复杂的或递归的行为。好处是可以用同样的发放处理对象的集合与其中的特定子对象,也可以用来把一批子对象组织成树形结构,并且使整个树都可被遍历。如下:
1 // DynamicGallery Class 2 var DynamicGallery =function (id) { // 实现Composite,GalleryItem组合对象类 3 this.children = []; 4 this.element = document.createElement('div'); 5 this.element.id = id; 6 this.element.className ='dynamic-gallery'; 7 } 8 DynamicGallery.prototype = { 9 // 实现Composite组合对象接口 10 add: function (child) {11 this.children.push(child);12 this.element.appendChild(child.getElement());13 },14 remove: function (child) {15 for (var node, i =0; node =this.getChild(i); i++) {16 if (node == child) {17 this.children.splice(i, 1);18 break;19 }20 }21 this.element.removeChild(child.getElement());22 },23 getChild: function (i) {24 returnthis.children[i];25 },26 // 实现DynamicGallery组合对象接口 27 hide: function () {28 for (var node, i =0; node =this.getChild(i); i++) {29 node.hide();30 }31 this.element.style.display ='none';32 },33 show: function () {34 this.element.style.display ='block';35 for (var node, i =0; node = getChild(i); i++) {36 node.show();37 }38 },39 // 帮助方法 40 getElement: function () {41 returnthis.element;42 }43 }
1 var GalleryImage =function (src) { // 实现Composite和GalleryItem组合对象中所定义的方法 2 this.element = document.createElement('img'); 3 this.element.className ='gallery-image'; 4 this.element.src = src; 5 } 6 GalleryImage.prototype = { 7 // 实现Composite接口 8 // 这些是叶结点,所以我们不用实现这些方法,我们只需要定义即可 9 add: function () { },10 remove: function () { },11 getChild: function () { },12 // 实现GalleryItem接口 13 hide: function () {14 this.element.style.display ='none';15 },16 show: function () {17 this.element.style.display ='';18 },19 // 帮助方法 20 getElement: function () {21 returnthis.element;22 }23 }
1 var topGallery =new DynamicGallery('top-gallery'); 2 topGallery.add(new GalleryImage('/img/image-1.jpg')); 3 topGallery.add(new GalleryImage('/img/image-2.jpg')); 4 topGallery.add(new GalleryImage('/img/image-3.jpg')); 5 var vacationPhotos =new DyamicGallery('vacation-photos'); 6 for(var i =0, i <30; i++){ 7 vacationPhotos.add(new GalleryImage('/img/vac/image-'+ i +'.jpg')); 8 } 9 topGallery.add(vacationPhotos); 10 topGallery.show(); 11 vacationPhotos.hide();
门面模式常常是开发人员最亲密的朋友,他几乎是所有javascript库的核心原则。门面模式有两个作用:一是简化类的接口;二是消除类与使用它的客户代码之间的耦合。示例如下:
1 function a() { 2 3 } 4 function b() { 5 6 } 7 function ab() { 8 a(); 9 b();10 }
适配器模式可以用来在现有接口和不兼容的类之间进行适配。从表面上看,适配器模式很像门面模式,都对别的对象进行包装并改变其呈现的接口。二者的区别在与它们如何改变接口,门面元素展现的是一个简化的接口,它并不提供额外的选择,而且有时为了方便完成常见任务它还会做出一些假定。而适配器则要把一个接口转换为另一个接口,它并不会过滤某些能力,也不会简化接口。
1 var str = { 2 a: 'a', 3 b: 'b', 4 c: 'c' 5 }; 6 function i(s1,s2,s3) { 7 console.log(s1 + ',' + s2 + ',' + s3); 8 } 9 function demo(o) {10 i(o.a,o.b,o.c);11 }
装饰者模式可用来透明地把对象包装在具有同样接口的另一个对象之中,装饰者可以用于为对象添加功能,可以用来代替大量子类。装饰者模式和组合模式有很多共同点,它们都与所包装的对象实现统一的接口并且会把任何方法条用传递给这些对象。可是组合模式用于把众多子对象组织为一个整体,而装饰者模式用于在不修改现有对象或从派生子类的前提下为其添加方法。如下:
1 var m = {};2 m.child = {};3 m.child.one = function() {};4 m.child.two = function() {};
享元模式最适合于解决因创建大量类似对象而累及性能的问题。通过把大量独立对象转化为少量共享对象,可以降低运行web应用程序所需的资源数量。
javascript设计模式中的示例:
1 //汽车登记示例 2 var Car =function(make,model,year,owner,tag,renewDate){ 3 this.make=make; 4 this.model=model; 5 this.year=year; 6 this.owner=owner; 7 this.tag=tag; 8 this.renewDate=renewDate; 9 }10 Car.prototype = {11 getMake:function(){12 returnthis.make;13 },14 getModel:function(){15 returnthis.model;16 },17 getYear:function(){18 returnthis.year;19 },20 transferOwner:function(owner,tag,renewDate){21 this.owner=owner;22 this.tag=tag;23 this.renewDate=renewDate;24 },25 renewRegistration:function(renewDate){26 this.renewDate=renewDate;27 }28 }29 //数据量小到没多大的影响,数据量大的时候对计算机内存会产生压力,下面介绍享元模式优化后30 //包含核心数据的Car类31 var Car=function(make,model,year){32 this.make=make;33 this.model=model;34 this.year=year;35 }36 Car.prototype={37 getMake:function(){38 returnthis.make;39 },40 getModel:function(){41 returnthis.model;42 },43 getYear:function(){44 returnthis.year;45 }46 }47 //中间对象,用来实例化Car类48 var CarFactory=(function(){49 var createdCars = {};50 return {51 createCar:function(make,model,year){52 var car=createdCars[make+"-"+model+"-"+year];53 return car ? car : createdCars[make +'-'+ model +'-'+ year] =(new Car(make,model,year));54 }55 }56 })();57 //数据工厂,用来处理Car的实例化和整合附加数据58 var CarRecordManager = (function() {59 var carRecordDatabase = {};60 return {61 addCarRecord:function(make,model,year,owner,tag,renewDate){62 var car = CarFactory.createCar(make, model, year);63 carRecordDatabase[tag]={64 owner:owner,65 tag:tag,66 renewDate:renewDate,67 car:car68 }69 },70 transferOwnership:function(tag, newOwner, newTag, newRenewDate){71 var record=carRecordDatabase[tag];72 record.owner = newOwner;73 record.tag = newTag;74 record.renewDate = newRenewDate;75 },76 renewRegistration:function(tag,newRenewDate){77 carRecordDatabase[tag].renewDate=newRenewDate;78 },79 getCarInfo:function(tag){80 return carRecordDatabase[tag];81 }82 }83 })();
代理是一个对象,它可以用来控制对另一个对象的访问。它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象。代理模式适合处理实例化比较费时的本体,也适合处理那些需要较长时间才能把数据载入用户界面的类。
javascript设计模式中的示例:
1 var Publication =new Interface('Publication', ['getIsbn', 'setIsbn', 'getTitle', 'setTitle', 'getAuthor', 'setAuthor', 'display']); 2 var Book =function(isbn, title, author) { 3 //... 4 } 5 // implements Publication 6 implements(Book,Publication); 7 8 /* Library interface. */ 9 var Library =new I
新闻热点
疑难解答