/ 昌里大金猪的空间 / Essential Javascript Design Patterns For Beginners [翻译]

Essential Javascript Design Patterns For Beginners [翻译]

2011-03-04 posted in [javascript]

本文地址:http://blog.163.com/jinlu_hz/blog/static/11383015220112492932225/
原文地址:http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/
原文作者:Addy Osmani

最近正在学习javascript设计模式,翻阅了不少资料,发现这篇文章比较适合教学入门,并且国内还没有人对其进行过翻译。
原文内容结构如下:
在此我准备挑选Design Patterns in JavaScript和A High-level View Of Design Patterns in jQuery2章进行翻译。初次翻译,译的不到位的地方请读者自动跳过或者直接阅读原文,本文仅供学习参考。

——以下为翻译——


接下来我们看一下近几年javascript中较为常用的几种设计模式。

要注意的是对于开发者在决定使用哪种模式时,并没有最理想,只有针对需求而言最合适的。
每种模式不尽相同,那么在此我尽可能以简练的语言让初学者以及开发人员能够从中获益。

以下是将要讨论的模式:
  • Creational Pattern创建型模式
  • Constructor Pattern构造函数模式
  • Singleton Pattern单例模式
  • Module Pattern模块模式
  • Revealing Module Pattern揭示模块模式
  • Observer Pattern观察者模式
  • Prototype Pattern原型模式
  • Command Pattern命令模式
  • DRY Pattern不重复模式
  • Facade Pattern门面模式
  • Factory Pattern工厂模式
  • Mixin Pattern混元模式
  • Decorator Pattern装饰者模式

The Creational Pattern(创建型模式)
该模式是其他一些模式的基础,也通俗易懂。正如你猜测的,创建型模式在应用程序中创建对象。在javascript中,传统的对象创建方法如下所示:
1var newObject = new Object(); //or
2var newObject = {};
3 
4newObject['someValue'] = 'Hello World';

很多时候,你有理由通过创建特定对象的方式来实现,但上述方式简化了创建过程,应用该模式创建非特定对象是多么的轻松简单。你只要简单地使用构造函数来实例化一个对象并为以后所用。

The Constructor Pattern(构造函数模式)


短语“构造函数”为大多数开发者所熟知了,然而如果你还是个初学者,在我们深入讨论该模式之前你可以先去复习一下构造函数的相关原理。构造函数被用来创建特定类型的对 象-构造函数准备为对象的使用做准备,也可以接受参数,这些参数当对象第一次创建时由构造函数获取并为成员变量的设值。这种思想在大多数编程语言中有示例,包括javascript。你可能熟知一些原生构造函数比如Object和Array。你亦可自定义构造函数用来定义你一些属性以及方法。

Basic Constructors基础构造函数
javascript中,通常用构造方法来创建实例对象。javascript不支持类的概念,却支持特定的构造方法。你能够通过简单加一个new作为前缀来调用一个构造函数,告诉javascript你想将普通函数变现地像构造函数一样,并且实例化一个由该函数定义一组变量的新对象。在构造函数中,关键字“this” 的引用指向正在创建的新对象。一个基础构造函数如下:
01function Car(model, year, miles){
02   this.model = model;
03   this.year    = year;
04   this.miles  = miles;
05   this.toString = function(){
06    return this.model + " has done " + this.miles + " miles";
07   };
08}
09  
10var civic = new Car("Honda Civic", 2009, 20000);
11var mondeo = new Car("Ford Mondeo", 2010, 5000);
12 
13console.log(civic.toString());
14console.log(mondeo.toString());

以上是个简单的构造函数示例,它有一些瑕疵。其中之一使继承变得困难,再者就是类似toString()一样的方法在每个使用Car的构造函数创建出来的新对象中被重定义了。

Constructors With Prototypes(带有原型的构造函数)

javascript中的Function有一个属性称为原型(prototype)。当调用javascript构造函数创建对象时,构造函数原型上所有的属性对于新对象来说都可见。用这种方式,多个能够访问相同原型的Car对象被成功创建了。于是我们能够将最初的示例改造如下:
01function Car(model, year, miles){
02   this.model = model;
03   this.year    = year;
04   this.miles  = miles;
05}
06 
07/*
08 Note here that we are using Object.prototype.newMethod rather than
09 Object.prototype so as to avoid redefining the prototype object
10*/
11Car.prototype.toString: function(){
12        return this.model + " has done " + this.miles + " miles";
13};
14  
15var civic = new Car("Honda Civic", 2009, 20000);
16var mondeo = new Car("Ford Mondeo", 2010, 5000);
17 
18console.log(civic.toString());

在此,toString()单个实例将被所有的Car对象所共用。

翻译 - Essential Javascript Design Patterns For Beginners(2)
The Singleton Pattern(单例模式)
传统的软件工程中,单例模式就是确保一个类中只有一个实例[意译]。如果实例已经存在,则返回该实例引用给对象。传统上,单例模式限制了类实例化一个对象。javascript 中,单体对象服务于将代码实现与全局命名空间隔离的命名空间提供者,目的是为方法提供单一访问入口。//The singleton doesn't provide a way for code that doesn't know about a previous reference to the singleton to easily retrieve it此处不知如何翻译这并不是对象或者由一个单体返回的'类',而是一个结构体。考虑一下为何封闭的变量不构成闭包,提供封闭环境方法作用域才是真正形成闭包。

javascript中的单例模式有许多迥异的形式,对该模式的研究也可能得出10种不同的结论。javascript中最简化的单例模式可以是一组聚集在一起的对象字面量,相关方法和属性如下所示:
  1. var mySingleton = {  
  2.     property1:"something",  
  3.     property2:"something else",  
  4.     method1:function(){  
  5.         console.log('hello world');  
  6.     }  


如果你想扩展一下,你可以通过封装变量和函数声明在一个闭包里来增加私有成员变量和方法,暴露公共部分即可,如下:
  1. var mySingleton = function(){  
  2.     
  3.     /* here are my private variables and methods */  
  4.     var privateVariable = 'something private';  
  5.     function showPrivate(){  
  6.         console.log(privateVariable);  
  7.     }  
  8.     
  9.     /* public variables and methods (which can access private variables and methods ) */  
  10.     return {  
  11.         publicMethod:function(){  
  12.             showPrivate();  
  13.         },  
  14.         publicVar:'the public can see this!'  
  15.     }  
  16. }  
  17.     
  18. var single = mySingleton();  
  19. single.publicMethod();  // logs 'something private'  
  20. console.log(single.publicVar); // logs 'the public can see this!' 

上述示例实现良好。再考虑一种场景,你只想按需实例化怎么办。为了节约系统资源,可以将实例化的相关代码实现置于另一个构造函数,如下所示:
  1. var Singleton =(function(){  
  2.     var instantiated;  
  3.     function init (){  
  4.         /*singleton code here*/  
  5.         return {  
  6.             publicMethod:function(){  
  7.                 console.log('hello world')  
  8.             },  
  9.             publicProperty:'test'  
  10.         }  
  11.     }  
  12.     
  13.     return {  
  14.         getInstance :function(){  
  15.             if (!instantiated){  
  16.                 instantiated = init();  
  17.             }  
  18.             return instantiated;  
  19.         }  
  20.     }  
  21. })()  
  22. /*calling public methods is then as easy as:*/  
  23. Singleton.getInstance.publicMethod(); 

那么,实际操作中还有哪些地方可以用到单例模式呢?当一个对象需要跨系统与其他模块协作时,该模式十分有用。如下:
  1. var SingletonTester = (function(){  
  2.   
  3.     //args: an object containing arguments for the singleton  
  4.     function Singleton(args){  
  5.       
  6.         //set args variable to args passed or empty object if none provided.  
  7.         var args = args ||  
  8.         {};  
  9.         //set the name parameter  
  10.         this.name = 'SingletonTester';  
  11.         //set the value of pointX  
  12.         this.pointX = args.pointX || 6; //get parameter from arguments or set default  
  13.         //set the value of pointY  
  14.         this.pointY = args.pointY || 10;  
  15.           
  16.     }  
  17.       
  18.     //this is our instance holder  
  19.     var instance;  
  20.       
  21.     //this is an emulation of static variables and methods  
  22.     var _static = {  
  23.         name: 'SingletonTester',  
  24.         //This is a method for getting an instance  
  25.           
  26.         //It returns a singleton instance of a singleton object  
  27.         getInstance: function(args){  
  28.             if (instance === undefined) {  
  29.                 instance = new Singleton(args);  
  30.             }  
  31.             return instance;  
  32.         }  
  33.     };  
  34.     return _static;  
  35. })();  
  36.   
  37. var singletonTest = SingletonTester.getInstance({  
  38.     pointX: 5  
  39. });  
  40. console.log(singletonTest.pointX); // outputs 5  


翻译 - Essential Javascript Design Patterns For Beginners(3)

The Module Pattern(模块模式)

在传统软件工程领域,模块模式最初是定义类的私有和公共封装的一种方式。
在javascript中,模块模式用于模拟类的概念,使得我们能够包括公共/私有方法以及变量在一个简单的对象内部。目的是从全局作用域中遮蔽特定部分。这将减少与页面其他脚本命名冲突的可能性。

更进一步来看公共与私有函数,模块模式允许我们构造能够访问模块内部的特定函数与变量,也就意味着可以杜绝外部实体访问这个“隐藏的”信息。

让我们来看一看模块模式通过创建一个在全局对象中自包含的模块的实现。在这里,代码的其他部分无法读取incrementCounter()和resetCounter()的值。counter变量实际上就像私有变量那样,完全从全局作用域隔离出来。它的存在是限制在模块的封闭性,于是只有上述那两个方法能够访问它的作用域。这些方法有效地被置于对应命名空间里,对于代码中的测试模块,我们需要以前缀加模块名来调用(例如testModule)。
  1. var testModule = (function(  
  2.     var counter = 0;  
  3.     return {  
  4.         incrementCounter: function() {  
  5.             return counter++;  
  6.         },  
  7.         resetCounter: function() {  
  8.             counter = 0  
  9.             counter = 0  
  10.         }  
  11.     };  
  12. ))();  
  13.    
  14. /test/  
  15. testModule.incrementCounter();  
  16. testModule.resetCounter(); 

当你使用模块模式时,定义一个简单的模板会很有用。下面这个示例涉及到命名空间,共有以及私有变量:
  1. var myNamespace = (function(){  
  2.     var myPrivateVar = 0;  
  3.         var myPrivateMethod = function(someText){  
  4.         console.log(someText);  
  5.     }  
  6.        
  7.     return {  
  8.         myPublicVar: "foo",  
  9.         myPublicFunction: function(bar){  
  10.             myPrivateVar++;  
  11.             myPrivateMethod(bar);  
  12.         }  
  13.     }  
  14. })(); 

还有一件微不足道的事是。模块模式最初是由Douglas Crockford 正式定义('JavaScript: The Good Parts, and more')。尽管可能我们已经使用过很多该模式的变种了。另一件事,如果你曾经使用过雅虎的YUI javascript框架,会发现一些类似特性,原因是模块模式对yui在创建组件时的影响很深。

所以,你以及已经得知为何单例模式很有用,但为何模块模式是一个好的选择呢?对于开发者,那面向对象背景思维要比实际封装更整洁,至少在javascript层面。其次,它支持私有数据。那么,在模块模式中,代码的公共部分能够访问私有部分,然而外界世界却无法访问类中的私有部分。//作者在这边讲了一个joke

模块模式的弊端,访问公共与私有成员的方式是不同的。当你想要改变可见性,实际上你不得不修改每一个用到成员变量的地方。你也不能访问函数中后来被增加进去的私有成员。也就是说,许多情况下,当正确地、确定对改进程序结构有帮助时,使用模块模式仍旧有用。示例:
  1. var someModule = (function(){  
  2.   
  3.     //private attributes  
  4.     var privateVar = 5;  
  5.       
  6.     //private methods  
  7.     var privateMethod = function(){  
  8.         return 'Private Test';  
  9.     };  
  10.       
  11.     return {  
  12.         //public attributes  
  13.         publicVar: 10,  
  14.         //public methods  
  15.         publicMethod: function(){  
  16.             return ' Followed By Public Test ';  
  17.         },  
  18.           
  19.         //let's access the private members  
  20.         getData: function(){  
  21.             return privateMethod() + this.publicMethod() + privateVar;  
  22.         }  
  23.     }  
  24. })(); //the parens here cause the anonymous function to execute and return  
  25. someModule.getData(); 

为进一步了解模块模式,强烈建议阅读Ben Cherry's JavaScript Module Pattern In-Depth一文。

The Revealing Module Pattern(揭秘模块模式)


现在你很可能已经熟悉了什么是模块模式。让我们再来看一下它的改进版本。
  1. / 
  2.  The idea here is that you have private methods 
  3.  which you want to expose as public methods. 
  4.   
  5.  What are are doing below is effectively defining 
  6.  a self-executing function and immediately returning 
  7.  the object. 
  8.  /  
  9. var myRevealingModule = function () {  
  10.     var name = "John Smith";  
  11.     var age = 40;  
  12.     function updatePerson() {  
  13.         name = "John Smith Updated";  
  14.     }  
  15.     function setPerson() {  
  16.         name = "John Smith Set";  
  17.     }  
  18.     function getPerson() {  
  19.         return name;  
  20.     }  
  21.     return {set:setPerson, get:getPerson};  
  22. }();  
  23.        
  24.     // Sample usage:  
  25. myRevealingModule.get();

The Observer pattern(观察者模式)

观察者模式允许一个对象(观察者)另一个对象(主体),从而建立一种“发布-订阅关系” 观察者能够从一个目标对象接受注册过的事件,当目标对象的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。发布/订阅模型在事件管理上显得非常实用。该模式的动机是使几个相关对象不通过紧耦合就维持一致性。

使用观察者你是的好处:
  • 支持简单的广播通信,自动通知所有已经订阅过的对象。
  • 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
  • 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

该模式的一点缺陷是,观察者之间互相不可见。由于目标对象与观察者间的动态联系,一旦有更新,他们之间的依赖性变得难以追踪。(作者的意思可能是,当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改)[拗口]。

尽管已经有许多正确使用观察者模式的例子了,再举一个学术界广泛应用的实例:电子表格应用(spreadsheet application),我们假想在google docs中使用了一组Ui控件:电子表格的公式栏(例如Formula),饼图(例如PieChart),条形图(例如BarGraph)。那些ui组件的数据源将被当作'ssSpreadsheetData'。ssFormula, ssPieChart和ssBarGraph都是观察者对象,'ssSpreadsheetData'则是目标主体。当数据发生变化时,ssSpreadsheet数据对象会通知它的观察者们自己的状态与他们产生了不一致。
再看一下javascript中运用到的观察者模式吧。下面的示例是发布/订阅模型的一个迷你版本(最初由twitter的Dustin Diaz编写,后根据我们的需求改编)。这个例子向你展示了该模式最有力的一门,demo示例如下:
观察者接口的实现:
  1. function Observer(){  
  2.     this.functions = [];  
  3. }  
  4.    
  5. Observer.prototype = {  
  6.     subscribe : function(fn) {  
  7.         this.functions.push(fn);  
  8.     },  
  9.        
  10.     unsubscribe : function(fn) {  
  11.         this.functions = this.functions.filter(  
  12.             function(el) {  
  13.                 if ( el !== fn ) {  
  14.                     return el;  
  15.                 }  
  16.             }  
  17.         );  
  18.     },  
  19.        
  20.     update : function(o, thisObj) {  
  21.         var scope = thisObj || window;  
  22.         this.functions.forEach(  
  23.             function(el) {  
  24.                 el.call(scope, o);  
  25.             }  
  26.         );  
  27.     }  
  28. }; 

订阅以及发布接口的实现:
  1. / 
  2.   Publishers are in charge of "publishing" eg: Creating the Event 
  3.   They're also in charge of "notifying" (firing the event) 
  4.  /  
  5. var obs = new Observer;  
  6. obs.update('here is some test information');  
  7.   
  8. / 
  9.   Subscribers basically... "subscribe" (or listen) 
  10.   And once they've been "notified" their callback functions are invoked 
  11.  /  
  12. var fn = function(){  
  13.     // my callback stuff  
  14. };  
  15. obs.subscribe(fn);  
  16.   
  17. / 
  18.   Unsubscribe if you no longer wish to be notified 
  19.  */  
  20. o.unsubscribe(fn);

Note:如果你对jquery中的发布/订阅模式实现有兴趣,建议去阅读一下Ben Alman's GitHub Gist

翻译 - Essential Javascript Design Patterns For Beginners(4)

The Module Pattern(模块模式)

在传统软件工程领域,模块模式最初是定义类的私有和公共封装的一种方式。
在javascript中,模块模式用于模拟类的概念,使得我们能够包括公共/私有方法以及变量在一个简单的对象内部。目的是从全局作用域中遮蔽特定部分。这将减少与页面其他脚本命名冲突的可能性。

更进一步来看公共与私有函数,模块模式允许我们构造能够访问模块内部的特定函数与变量,也就意味着可以杜绝外部实体访问这个“隐藏的”信息。

让我们来看一看模块模式通过创建一个在全局对象中自包含的模块的实现。在这里,代码的其他部分无法读取incrementCounter()和resetCounter()的值。counter变量实际上就像私有变量那样,完全从全局作用域隔离出来。它的存在是限制在模块的封闭性,于是只有上述那两个方法能够访问它的作用域。这些方法有效地被置于对应命名空间里,对于代码中的测试模块,我们需要以前缀加模块名来调用(例如testModule)。
  1. var testModule = (function(  
  2.     var counter = 0;  
  3.     return {  
  4.         incrementCounter: function() {  
  5.             return counter++;  
  6.         },  
  7.         resetCounter: function() {  
  8.             counter = 0  
  9.             counter = 0  
  10.         }  
  11.     };  
  12. ))();  
  13.    
  14. /*test*/  
  15. testModule.incrementCounter();  
  16. testModule.resetCounter(); 

当你使用模块模式时,定义一个简单的模板会很有用。下面这个示例涉及到命名空间,共有以及私有变量:
  1. var myNamespace = (function(){  
  2.     var myPrivateVar = 0;  
  3.         var myPrivateMethod = function(someText){  
  4.         console.log(someText);  
  5.     }  
  6.        
  7.     return {  
  8.         myPublicVar: "foo",  
  9.         myPublicFunction: function(bar){  
  10.             myPrivateVar++;  
  11.             myPrivateMethod(bar);  
  12.         }  
  13.     }  
  14. })(); 

还有一件微不足道的事是。模块模式最初是由Douglas Crockford 正式定义('JavaScript: The Good Parts, and more')。尽管可能我们已经使用过很多该模式的变种了。另一件事,如果你曾经使用过雅虎的YUI javascript框架,会发现一些类似特性,原因是模块模式对yui在创建组件时的影响很深。

所以,你以及已经得知为何单例模式很有用,但为何模块模式是一个好的选择呢?对于开发者,那面向对象背景思维要比实际封装更整洁,至少在javascript层面。其次,它支持私有数据。那么,在模块模式中,代码的公共部分能够访问私有部分,然而外界世界却无法访问类中的私有部分。//作者在这边讲了一个joke

模块模式的弊端,访问公共与私有成员的方式是不同的。当你想要改变可见性,实际上你不得不修改每一个用到成员变量的地方。你也不能访问函数中后来被增加进去的私有成员。也就是说,许多情况下,当正确地、确定对改进程序结构有帮助时,使用模块模式仍旧有用。示例:
  1. var someModule = (function(){  
  2.   
  3.     //private attributes  
  4.     var privateVar = 5;  
  5.       
  6.     //private methods  
  7.     var privateMethod = function(){  
  8.         return 'Private Test';  
  9.     };  
  10.       
  11.     return {  
  12.         //public attributes  
  13.         publicVar: 10,  
  14.         //public methods  
  15.         publicMethod: function(){  
  16.             return ' Followed By Public Test ';  
  17.         },  
  18.           
  19.         //let's access the private members  
  20.         getData: function(){  
  21.             return privateMethod() + this.publicMethod() + privateVar;  
  22.         }  
  23.     }  
  24. })(); //the parens here cause the anonymous function to execute and return  
  25. someModule.getData(); 

为进一步了解模块模式,强烈建议阅读Ben Cherry's JavaScript Module Pattern In-Depth一文。

The Revealing Module Pattern(揭秘模块模式)


现在你很可能已经熟悉了什么是模块模式。让我们再来看一下它的改进版本。
  1. /* 
  2.  The idea here is that you have private methods 
  3.  which you want to expose as public methods. 
  4.   
  5.  What are are doing below is effectively defining 
  6.  a self-executing function and immediately returning 
  7.  the object. 
  8.  */  
  9. var myRevealingModule = function () {  
  10.     var name = "John Smith";  
  11.     var age = 40;  
  12.     function updatePerson() {  
  13.         name = "John Smith Updated";  
  14.     }  
  15.     function setPerson() {  
  16.         name = "John Smith Set";  
  17.     }  
  18.     function getPerson() {  
  19.         return name;  
  20.     }  
  21.     return {set:setPerson, get:getPerson};  
  22. }();  
  23.        
  24.     // Sample usage:  
  25. myRevealingModule.get();

The Observer pattern(观察者模式)

观察者模式允许一个对象(观察者)另一个对象(主体),从而建立一种“发布-订阅关系” 观察者能够从一个目标对象接受注册过的事件,当目标对象的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。发布/订阅模型在事件管理上显得非常实用。该模式的动机是使几个相关对象不通过紧耦合就维持一致性。

使用观察者你是的好处:
  • 支持简单的广播通信,自动通知所有已经订阅过的对象。
  • 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
  • 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

该模式的一点缺陷是,观察者之间互相不可见。由于目标对象与观察者间的动态联系,一旦有更新,他们之间的依赖性变得难以追踪。(作者的意思可能是,当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改)[拗口]。

尽管已经有许多正确使用观察者模式的例子了,再举一个学术界广泛应用的实例:电子表格应用(spreadsheet application),我们假想在google docs中使用了一组Ui控件:电子表格的公式栏(例如Formula),饼图(例如PieChart),条形图(例如BarGraph)。那些ui组件的数据源将被当作'ssSpreadsheetData'。ssFormula, ssPieChart和ssBarGraph都是观察者对象,'ssSpreadsheetData'则是目标主体。当数据发生变化时,ssSpreadsheet数据对象会通知它的观察者们自己的状态与他们产生了不一致。
再看一下javascript中运用到的观察者模式吧。下面的示例是发布/订阅模型的一个迷你版本(最初由twitter的Dustin Diaz编写,后根据我们的需求改编)。这个例子向你展示了该模式最有力的一门,demo示例如下:
观察者接口的实现:
  1. function Observer(){  
  2.     this.functions = [];  
  3. }  
  4.    
  5. Observer.prototype = {  
  6.     subscribe : function(fn) {  
  7.         this.functions.push(fn);  
  8.     },  
  9.        
  10.     unsubscribe : function(fn) {  
  11.         this.functions = this.functions.filter(  
  12.             function(el) {  
  13.                 if ( el !== fn ) {  
  14.                     return el;  
  15.                 }  
  16.             }  
  17.         );  
  18.     },  
  19.        
  20.     update : function(o, thisObj) {  
  21.         var scope = thisObj || window;  
  22.         this.functions.forEach(  
  23.             function(el) {  
  24.                 el.call(scope, o);  
  25.             }  
  26.         );  
  27.     }  
  28. }; 

订阅以及发布接口的实现:
  1. /* 
  2.  * Publishers are in charge of "publishing" eg: Creating the Event 
  3.  * They're also in charge of "notifying" (firing the event) 
  4.  */  
  5. var obs = new Observer;  
  6. obs.update('here is some test information');  
  7.   
  8. /* 
  9.  * Subscribers basically... "subscribe" (or listen) 
  10.  * And once they've been "notified" their callback functions are invoked 
  11.  */  
  12. var fn = function(){  
  13.     // my callback stuff  
  14. };  
  15. obs.subscribe(fn);  
  16.   
  17. /* 
  18.  * Unsubscribe if you no longer wish to be notified 
  19.  */  
  20. o.unsubscribe(fn);

Note:如果你对jquery中的发布/订阅模式实现有兴趣,建议去阅读一下Ben Alman's GitHub Gist

翻译 - Essential Javascript Design Patterns For Beginners(4)

The Facade Pattern(门面模式

门面模式简化类中接口并对接口与调用者进行解耦。门面经常被当作是开发者模式工作包里的必备,将一些复杂操作封装起来,并创建一个简单的接口提供给自己。
门面模式在那些跨浏览器兼容性的javascript api中有所体现。门面提供了一种间接与子系统交互的方式,从而避免因直接访问子系统而产生不必要的错误。

门面的一大优势在于便于使用,本身也比较轻量级。但模式本身亦有缺陷。当门面模式被开发者连续使用时会产生一定的性能问题,因为在每次调用时都会检测功能的可用性。
下面是一段未优化过的代码,在此我们会运用门面模式简化一遍。通过检测浏览器特性的思想来创建一个跨浏览器的公用方法。
  1. var addMyEvent = function(el, ev, fn){  
  2.     if (el.addEventListener) {  
  3.         el.addEventListener(ev, fn, false);  
  4.     }  
  5.     else   
  6.         if (el.attachEvent) {  
  7.             el.attachEvent('on' + ev, fn);  
  8.         }  
  9.         else {  
  10.             el['on' + ev] = fn;  
  11.         }  
  12. }; 

The Factory Pattern(工厂模式


与创建型模式类似,工厂模式创建大量对象(视为工厂里的产品)时无需指定对象细节。
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式负责将大量有共同接口的类实例化,而且不必事先知道每次是要实例化哪一个类的模式[意译]。

下面这个例子中,先用原始的构造函数模式演示一下,然后再运用工厂模式进行优化:
  1. var Car = (function(){  
  2.     var Car = function(model, year, miles){  
  3.         this.model = model;  
  4.         this.year = year;  
  5.         this.miles = miles;  
  6.     };  
  7.     return function(model, year, miles){  
  8.         return new Car(model, year, miles);  
  9.     }  
  10. })();  
  11.   
  12. var civic = new Car("Honda Civic", 2009, 20000);  
  13. var mondeo = new Car("Ford Mondeo", 2010, 5000); 

When To Use This Pattern什么时候该用

以下几种情景下工厂模式特别有用:
  • 对象的构建十分复杂
  • 需要依赖具体环境创建不同实例
  • 处理大量具有相同属性的小对象

When Not To Use This Pattern什么时候不该用
不滥用运用工厂模式,有时候仅仅只是给代码增加了不必要的复杂度,同时使得测试难以运行下去。

The Mixin Pattern(混元模式

传统的面向对象编程语言中,混元无非就是将类中一些功能掺杂给子类,利用利mixin机制模拟可以实现多继承。
接下来的实例中有一个无任何方法的Car类,同时还包含一个构造函数称为'mixin',我们将增加Car类使其能够访问mixin内的函数对象。这段代码阐明了在javascript中如何不使用传统的继承或者通过在构造函数添加重复代码来实现功能上的扩展。
  1. / Car Class /  
  2. var Car = function(settings){  
  3.     this.model = settings.model || 'no model provided';  
  4.     this.colour = settings.colour || 'no colour provided';  
  5. };  
  6.   
  7. / Mixin Class /  
  8. var Mixin = function(){  
  9. };  
  10. Mixin.prototype = {  
  11.     driveForward: function(){  
  12.         console.log('drive forward');  
  13.     },  
  14.     driveBackward: function(){  
  15.         console.log('drive backward');  
  16.     }  
  17. };  
  18.   
  19.   
  20. / Augment existing class with a method from another class /  
  21. function augment(receivingClass, givingClass){  
  22.     / only provide certain methods /  
  23.     if (arguments[2]) {  
  24.         for (var i = 0, len = arguments.length; i < len; i++) {  
  25.             receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];  
  26.         }  
  27.     }  
  28.     / provide all methods/  
  29.     else {  
  30.         for (methodName in givingClass.prototype) {  
  31.             / check to make sure the receiving class doesn't 
  32.              have a method of the same name as the one currently 
  33.              being processed /  
  34.             if (!receivingClass.prototype[methodName]) {  
  35.                 receivingClass.prototype[methodName] = givingClass.prototype[methodName];  
  36.             }  
  37.         }  
  38.     }  
  39. }  
  40.   
  41.   
  42. / Augment the Car class to have the methods 'driveForward' and 'driveBackward'/  
  43. augment(Car, Mixin, 'driveForward''driveBackward');  
  44.   
  45. / Create a new Car /  
  46. var vehicle = new Car({  
  47.     model: 'Ford Escort',  
  48.     colour: 'blue'  
  49. });  
  50.   
  51. / Test to make sure we now have access to the methods/  
  52. vehicle.driveForward();  
  53. vehicle.driveBackward(); 

 
The Decorator Pattern(装饰者模式


装饰者提供比继承更有弹性的替代方案。 装饰者可以使用另一个对象来包装,动态地将责任附加到对象上。
该模式可以在被被装饰前面或者后面加上自己的行为以达到特定的目的。
那么装饰者模式有什么好处呢?前面说了,装饰器是一种实现继承的替代方案。当脚本运行时,在子类中增加行为会影响原有类所有的实例,装饰过程却不然。取而代之的是它能给不同对象各自添加新行为。如下代码所示:
  1. //The class we're going to decorate  
  2. function Macbook(){  
  3.     this.cost = function(){  
  4.         return 1000;  
  5.     };  
  6. }  
  7.   
  8. function Memory(macbook){  
  9.     this.cost = function(){  
  10.         return macbook.cost() + 75;  
  11.     };  
  12. }  
  13.   
  14. function BlurayDrive(macbook){  
  15.     this.cost = function(){  
  16.         return macbook.cost() + 300;  
  17.     };  
  18. }  
  19.   
  20.   
  21. function Insurance(macbook){  
  22.     this.cost = function(){  
  23.         return macbook.cost() + 250;  
  24.     };  
  25. }  
  26.   
  27.   
  28. // Sample usage  
  29. var myMacbook = new Insurance(new BlurayDrive(new Memory(new Macbook())));  
  30. console.log(myMacbook.cost()); 

下面是另一个实例,当我们在装饰器对象上调用performTask时,它不仅具有一些装饰者的行为,同时也调用了源对象的performTask函数。
  1. function ConcreteClass(){  
  2.     this.performTask = function(){  
  3.         this.preTask();  
  4.         console.log('doing something');  
  5.         this.postTask();  
  6.     }  
  7. }  
  8.   
  9. function AbstractDecorator(decorated){  
  10.     this.performTask = function(){  
  11.         decorated.performTask();  
  12.     }  
  13. }  
  14.   
  15. function ConcreteDecoratorClass(decorated){  
  16.     this.base = AbstractDecorator;  
  17.     this.base(decorated);  
  18.       
  19.     this.preTask = function(){  
  20.         console.log('pre-calling..');  
  21.     }  
  22.       
  23.     this.postTask = function(){  
  24.         console.log('post-calling..');  
  25.     }  
  26.       
  27. }  
  28.   
  29. var concrete = new ConcreteClass();  
  30. var decorator1 = new ConcreteDecoratorClass(concrete);  
  31. var decorator2 = new ConcreteDecoratorClass(decorator1);  
  32. decorator2.performTask(); 

翻译 - Essential Javascript Design Patterns For Beginners(6)

The Prototype Pattern(原型模式)

原型模式通过拷贝其他对象的原型创建新的对象。原型对象本身是每个构造函数构造对象的设计根本(蓝图)。比方说构造函数的包含一个名为“name”的属性(如下代码所示)那么每个被同一个构造函数创建出来的对象会拥有相同的属性。

让我们再看一下现有不仅仅是javascript领域的学术文章中原型模式的定义,你会发现一些超出语言范畴的概念比如类。实际生活中原型继承避免了类的使用。这不是一个'定义'也不是一个核心组成点//不太明白作者的意思。我们只是简单的创建现有函数对象的一些拷贝。

运用原型模式其中有一个好处是我们正在运用javascript能够提供的语言优势,而不是模仿其他语言的功能(一些设计模式的实现上进行了模仿)。使得继承轻松实现,同时对于性能的提升有所帮助。在一个目标对象中定义了一个函数之后,就能创建一系列具有相同引用的子对象,而不是各自拷贝一份。

真正的原型式继承,如ECMAScript 5 定义的,需要使用Object.create,这个函数是最近才被添加进语言内部的。Object.create 创建了一个具有特定原型以及某些特定属性的对象(比如Object.create(prototype, optionalDescriptorObjects))。如下所示:
  1. /*No need for capitalization as it's not a constructor*/  
  2. var someCar = {  
  3.   drive: function() {};  
  4.   name: 'Mazda 3'     
  5. };  
  6.    
  7. /*Use Object.create to generate a new car*/  
  8. var anotherCar = Object.create(someCar);  
  9. anotherCar.name = 'Toyota Camry'

Object.create能够简单实现一些高级特性比如多重继承。你可以通过传入第二个所需参数实例化对象的一些属性。
  1. var vehicle = {  
  2.     getModel: function(){  
  3.         console.log('The model of this vehicle is..' + this.model);  
  4.     }  
  5. };  
  6.   
  7. var car = Object.create(vehicle, {  
  8.     'id': {  
  9.         value: MY_GLOBAL.nextId(),  
  10.         enumerable: true /*writable:false, configurable:false by default*/  
  11.     },  
  12.     'model': {  
  13.         value: 'Ford',  
  14.         enumerable: true  
  15.     }  
  16. }); 

在此Object.defineProperties和Object.defineProperty2个函数都是以类似的语法实例化一些对象的,使得能够设置一些属性例如enumerable, writable或者configurable.

如果你希望不运用Object.create来实现原型模式,你可以如下所示进行模拟:
  1. var vehiclePrototype = {  
  2.     init: function(carModel) {  
  3.         this.model = carModel;  
  4.     },  
  5.     getModel: function() {  
  6.         console.log('The model of this vehicle is..' + this.model);  
  7.     }  
  8. };  
  9.    
  10.    
  11. function vehicle(model) {  
  12.     function F() {};  
  13.     F.prototype = vehiclePrototype;  
  14.     var f = new F;  
  15.     f.init(model);  
  16.     return f;  
  17. }  
  18.    
  19. var car = vehicle('Ford Escort');  
  20. var.getModel(); //此处有明显的语法错误

The Command Pattern(命令模式

模式模式旨在封装函数的调用、请求和操作成一个单一的对象,然后对这个对象进行一系列的处理。此外,可以通过调用实现具体函数的对象来解耦命令对象与接收对象。

如果你还未能理解具体类,那么用基于类的编程语言以及抽象类的相关思想来解释最好了。抽象类中定义了一个接口,未必会向所有的成员函数提供相关实现。它的表现和从中衍生出的基类一样。一个实现某些尚未实现功能的衍生类被称为具体类(这些概念与装饰者模式和原型模式类似)。

接下来通过一个简单的车辆购买服务来展示这个命令模式。
  1. $(function(){  
  2.   
  3.     var CarManager = {  
  4.       
  5.         /* request information */  
  6.         requestInfo: function(model, id){  
  7.             return 'The information for ' + model + ' with ID ' + id + ' is foobar';  
  8.         },  
  9.           
  10.         /* purchase the car */  
  11.         buyVehicle: function(model, id){  
  12.             return 'You have successfully purchased Item ' + id + ', a ' + 'model';  
  13.         },  
  14.           
  15.         /* arrange a viewing */  
  16.         arrangeViewing: function(model, id){  
  17.             return 'You have successfully booked a viewing of ' + model + ' ( ' + id + ' ) ';  
  18.         }   
  19.     };  
  20. })(); 
来看一下上述代码,通过调用函数来简单执行manager的命令,然而在一些情况下,我们并不想直接调用对象内部的方法。这样会增加对象与对象间的依赖。现在我们来扩展一下这个CarManager 使其能够接受任何来自包括model和car ID 的CarManager对象的处理请求。可以这么实现:
CarManager.execute({commandType: "buyVehicle", operand1: 'Ford Escort', operand2: '453543'}); 
我们为每个结构的"CarManager.execute"增加一个方法:
  1. CarManager.execute = function(command){  
  2.     return CarManager[command.request](command.model, command.carID);  
  3. }; 

最终demo如下所示:
  1. CarManager.execute({request: "arrangeViewing", model: 'Ferrari', carID: '145523'});   
  2. CarManager.execute({request: "requestInfo", model: 'Ford Mondeo', carID: '543434'});     
  3. CarManager.execute({request: "requestInfo", model: 'Ford Escort', carID: '543434'});     
  4. CarManager.execute({request: "buyVehicle", model: 'Ford Escort', carID: '543434'}); 

The DRY Pattern(不重复原则

开发者在程序里写大段重复代码,这种事情时有发生,因为你的脚本与应用可能要执行类似的操作。重复性代码的编写降低了生产力,使得开发者几乎没有时间增添新的功能,重构迫在眉睫。
DRY大致就是指一段代码应该只做一件事情。如果要实现一个特定需求,就不应该在应用里到处散落重复代码。

当DRY成功地运用时,任何元素的修改不会改变其他那些逻辑上不相干的元素。代码中的相关元素应该随着需求同步变更。【作者有点啰嗦】
以jquery为例:
Non-DRY
  1. /*Let's store some default values in an array*/  
  2. var defaultSettings = {};  
  3. defaultSettings['carModel'] = 'Mercedes';  
  4. defaultSettings['carYear'] = 2010;  
  5. defaultSettings['carMiles'] = 5000;  
  6. defaultSettings['carTint'] = 'Metallic Blue';  
  7.   
  8. /*Let's do something with this data if a checkbox is clicked*/  
  9. $('.someCheckbox').click(function(){  
  10.   
  11.     if (this.checked) {  
  12.         $('#input_carModel').val(activeSettings.carModel);  
  13.         $('#input_carYear').val(activeSettings.carYear);  
  14.         $('#input_carMiles').val(activeSettings.carMiles);  
  15.         $('input_#carTint').val(activeSettings.carTint);  
  16.           
  17.     }  
  18.     else {  
  19.       
  20.         $('#input_carModel').val('');  
  21.         $('#input_carYear').val('');  
  22.         $('#input_carMiles').val('');  
  23.         $('#input_carTint').val('');  
  24.     }  
  25. }); 

DRY

  1. $('.someCheckbox').click(function(){  
  2.     var checked = this.checked;  
  3.     /* 
  4.      What are we repeating? 
  5.      1. input_ precedes each field name 
  6.      2. accessing the same array for settings 
  7.      3. repeating value resets 
  8.       
  9.      What can we do? 
  10.      1. programmatically generate the field names 
  11.      2. access array by key 
  12.      3. merge this call using terse coding (ie. if checked, 
  13.      set a value, otherwise don't) 
  14.      */  
  15.     $.each(['carModel''carYear''carMiles''carTint'], function(i, key){  
  16.         $('#input_' + v).val(checked ? defaultSettings[key] : '');  
  17.     });  
  18. }); 


翻译 - Essential Javascript Design Patterns For Beginners(5)

The Facade Pattern(门面模式

门面模式简化类中接口并对接口与调用者进行解耦。门面经常被当作是开发者模式工作包里的必备,将一些复杂操作封装起来,并创建一个简单的接口提供给自己。
门面模式在那些跨浏览器兼容性的javascript api中有所体现。门面提供了一种间接与子系统交互的方式,从而避免因直接访问子系统而产生不必要的错误。

门面的一大优势在于便于使用,本身也比较轻量级。但模式本身亦有缺陷。当门面模式被开发者连续使用时会产生一定的性能问题,因为在每次调用时都会检测功能的可用性。
下面是一段未优化过的代码,在此我们会运用门面模式简化一遍。通过检测浏览器特性的思想来创建一个跨浏览器的公用方法。
  1. var addMyEvent = function(el, ev, fn){  
  2.     if (el.addEventListener) {  
  3.         el.addEventListener(ev, fn, false);  
  4.     }  
  5.     else   
  6.         if (el.attachEvent) {  
  7.             el.attachEvent('on' + ev, fn);  
  8.         }  
  9.         else {  
  10.             el['on' + ev] = fn;  
  11.         }  
  12. }; 

The Factory Pattern(工厂模式


与创建型模式类似,工厂模式创建大量对象(视为工厂里的产品)时无需指定对象细节。
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式负责将大量有共同接口的类实例化,而且不必事先知道每次是要实例化哪一个类的模式[意译]。

下面这个例子中,先用原始的构造函数模式演示一下,然后再运用工厂模式进行优化:
  1. var Car = (function(){  
  2.     var Car = function(model, year, miles){  
  3.         this.model = model;  
  4.         this.year = year;  
  5.         this.miles = miles;  
  6.     };  
  7.     return function(model, year, miles){  
  8.         return new Car(model, year, miles);  
  9.     }  
  10. })();  
  11.   
  12. var civic = new Car("Honda Civic", 2009, 20000);  
  13. var mondeo = new Car("Ford Mondeo", 2010, 5000); 

When To Use This Pattern什么时候该用

以下几种情景下工厂模式特别有用:
  • 对象的构建十分复杂
  • 需要依赖具体环境创建不同实例
  • 处理大量具有相同属性的小对象

When Not To Use This Pattern什么时候不该用
不滥用运用工厂模式,有时候仅仅只是给代码增加了不必要的复杂度,同时使得测试难以运行下去。

The Mixin Pattern(混元模式

传统的面向对象编程语言中,混元无非就是将类中一些功能掺杂给子类,利用利mixin机制模拟可以实现多继承。
接下来的实例中有一个无任何方法的Car类,同时还包含一个构造函数称为'mixin',我们将增加Car类使其能够访问mixin内的函数对象。这段代码阐明了在javascript中如何不使用传统的继承或者通过在构造函数添加重复代码来实现功能上的扩展。
  1. /* Car Class */  
  2. var Car = function(settings){  
  3.     this.model = settings.model || 'no model provided';  
  4.     this.colour = settings.colour || 'no colour provided';  
  5. };  
  6.   
  7. /* Mixin Class */  
  8. var Mixin = function(){  
  9. };  
  10. Mixin.prototype = {  
  11.     driveForward: function(){  
  12.         console.log('drive forward');  
  13.     },  
  14.     driveBackward: function(){  
  15.         console.log('drive backward');  
  16.     }  
  17. };  
  18.   
  19.   
  20. /* Augment existing class with a method from another class */  
  21. function augment(receivingClass, givingClass){  
  22.     /* only provide certain methods */  
  23.     if (arguments[2]) {  
  24.         for (var i = 0, len = arguments.length; i < len; i++) {  
  25.             receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];  
  26.         }  
  27.     }  
  28.     /* provide all methods*/  
  29.     else {  
  30.         for (methodName in givingClass.prototype) {  
  31.             /* check to make sure the receiving class doesn't 
  32.              have a method of the same name as the one currently 
  33.              being processed */  
  34.             if (!receivingClass.prototype[methodName]) {  
  35.                 receivingClass.prototype[methodName] = givingClass.prototype[methodName];  
  36.             }  
  37.         }  
  38.     }  
  39. }  
  40.   
  41.   
  42. /* Augment the Car class to have the methods 'driveForward' and 'driveBackward'*/  
  43. augment(Car, Mixin, 'driveForward''driveBackward');  
  44.   
  45. /* Create a new Car */  
  46. var vehicle = new Car({  
  47.     model: 'Ford Escort',  
  48.     colour: 'blue'  
  49. });  
  50.   
  51. /* Test to make sure we now have access to the methods*/  
  52. vehicle.driveForward();  
  53. vehicle.driveBackward(); 

 
The Decorator Pattern(装饰者模式


装饰者提供比继承更有弹性的替代方案。 装饰者可以使用另一个对象来包装,动态地将责任附加到对象上。
该模式可以在被被装饰前面或者后面加上自己的行为以达到特定的目的。
那么装饰者模式有什么好处呢?前面说了,装饰器是一种实现继承的替代方案。当脚本运行时,在子类中增加行为会影响原有类所有的实例,装饰过程却不然。取而代之的是它能给不同对象各自添加新行为。如下代码所示:
  1. //The class we're going to decorate  
  2. function Macbook(){  
  3.     this.cost = function(){  
  4.         return 1000;  
  5.     };  
  6. }  
  7.   
  8. function Memory(macbook){  
  9.     this.cost = function(){  
  10.         return macbook.cost() + 75;  
  11.     };  
  12. }  
  13.   
  14. function BlurayDrive(macbook){  
  15.     this.cost = function(){  
  16.         return macbook.cost() + 300;  
  17.     };  
  18. }  
  19.   
  20.   
  21. function Insurance(macbook){  
  22.     this.cost = function(){  
  23.         return macbook.cost() + 250;  
  24.     };  
  25. }  
  26.   
  27.   
  28. // Sample usage  
  29. var myMacbook = new Insurance(new BlurayDrive(new Memory(new Macbook())));  
  30. console.log(myMacbook.cost()); 

下面是另一个实例,当我们在装饰器对象上调用performTask时,它不仅具有一些装饰者的行为,同时也调用了源对象的performTask函数。
  1. function ConcreteClass(){  
  2.     this.performTask = function(){  
  3.         this.preTask();  
  4.         console.log('doing something');  
  5.         this.postTask();  
  6.     }  
  7. }  
  8.   
  9. function AbstractDecorator(decorated){  
  10.     this.performTask = function(){  
  11.         decorated.performTask();  
  12.     }  
  13. }  
  14.   
  15. function ConcreteDecoratorClass(decorated){  
  16.     this.base = AbstractDecorator;  
  17.     this.base(decorated);  
  18.       
  19.     this.preTask = function(){  
  20.         console.log('pre-calling..');  
  21.     }  
  22.       
  23.     this.postTask = function(){  
  24.         console.log('post-calling..');  
  25.     }  
  26.       
  27. }  
  28.   
  29. var concrete = new ConcreteClass();  
  30. var decorator1 = new ConcreteDecoratorClass(concrete);  
  31. var decorator2 = new ConcreteDecoratorClass(decorator1);  
  32. decorator2.performTask(); 

翻译 - Essential Javascript Design Patterns For Beginners(6)
Design Patterns in jQuery-JQuery中的设计模式

Module Pattern(模块模式
模块模式基于封装的思想,它将模块封装在内部,与页面上的其他模块不产生任何冲突与影响。下面是jquery中的模块封装的一个实例:
  1. $(function(){  
  2.     var itemClass = (function(){  
  3.         var someItem = $('#item');  
  4.         return{  
  5.             thisItem: function(){  
  6.                 thisItem = document.createElement("div");  
  7.                 $(thisItem)  
  8.                     .html("test")  
  9.                     .appendTo("#container");  
  10.             }  
  11.         }  
  12.     })();  
  13. }); 

Lazy Initialization(延迟实例化

延迟实例化是必要时才实例化一个实例,创建这些实例通常需要一定的资源开销。举个例子, jquery中的.ready()方法只会在dom完全加载后被执行。
  1. $(document).ready(function(){  
  2.     $('#content').fadeIn();  
  3. }); 
The Composite Pattern(组合模式
组合模式以同样的方式对待对象组中的每一个对象。这个模式允许你以相同的方式处理单个对象和对象组合。在jquery中,可以以相同的方式处理单个dom元素或者一组dom元素。示例:
  1. $('#someDiv').addClass('active'); // a single element  
  2. $('div').addClass('active'); // a collection of elements 

The Wrapper Pattern(包裹模式
包裹模式将一个类中的接口转化成兼容性的接口。根本上来看,包裹模式允许将一些原本无法共同正常运行的类能够运行良好。包装器将其接口转化成原始接口,实现所需的代码量通常非常少。
  1. $('.container').css({  
  2.     opacity: .5 //apply opacity in modern browsers (eg. Chrome, FireFox) but use filter for IE  
  3. }); 

The Facade Pattern(门面模式
门面模式一般在面向对象编程中被用到,门面是一个向大段代码(比如一个库)提供更简易接口的对象。jquery库中到处可见门面模式,使方法更易用易懂,可读性也大大增强。实例:
  1. $.get();  
  2. $.post();  
  3. $.getJSON();  
  4. $.getScript(); 

The Observer pattern(观察者模式
观察者模式有多个依赖者,这多个依赖者(观察者)对象同时监听某一个主题对象,并且在其状态改变时让他们能够自动更新。通常通过调用他们自身的某个方法得以实现。观察者模式也称为发布/订阅模式。
  1. //Here jQuery makes use of its event system on top of DOM events  
  2.    $('.button').click(function(){})  
  3.    $('.button').trigger('click'function(){}) 

The Iterator Pattern(迭代器模式

迭代器模式提供一种方法有序访问一个聚集中元素,而不暴露聚集的内部对象。迭代器封装了迭代时的内部结构。以jquery的.each()迭代器为例,你实际上能够使用潜藏在.each()函数后的代码对集合进行遍历,而无需深入了解代码背后的机制。
  1. $.each(function(){});  
  2. $('.items').each(function(){}); 

The Strategy Pattern(策略模式

策略模式在执行时会选择一种特定算法。模式的目的在于提供一系列的算法,并将每一个算法封装起来,它们之间很容易相互替换。你可能会认为该模式最大的好处算法的变化不会影响到使用算法的开发者。例如,jquery中的toggle()允许开发人员给匹配的元素绑定2种2种以上的处理函数,目的是在不同的点击操作[alternate clicks]时执行相应函数。该策略允许使用独立于客户端内部的可替代算法。
$('#container').toggle(function(){}, function(){}); 

The Proxy  Pattern(代理模式
代理模式给某一对象提供代理对象,并由代理对象控制具体对象的引用[from javaeye]。代理几乎可以是任何对象:文件,资源,内存中的对象,或者是一些难以复制的东西。jquery中的.proxy()方法接受一个函数,然后返回一个具有特定上下文的新函数。
$.proxy(function(){}, obj);

The Builder Pattern(建造者模式
建造者模式抽象了创建各类对象的步骤,而这些步骤的实现手段各异。实例:
$('< div class= "foo"> bar < /div>'); 

The Prototype Pattern(原型模式
原型模式适用在系统中要创建大量的对象,这些对象之间具有几乎完全相同的功能时。该模式本质上用来避免创建一些一般情况下比较耗资源的、过度复杂的对象。接下来的代码展示扩展了jquery.fn
  1. $.fn.plugin = function(){}  
  2. $('#container').plugin(); 

The Flyweight Pattern(享元模式

该模式尽可能共享信息用以最小化系统的内存使用。大量使用重复对象消耗系统内存被认为是不可接受的。常常有一些对象的状态能够被共享,这些数据应该保存至外部数据结构中用以必要时传递至享元对象。// The userConfig is shared here:  
  1.   
  2. $.fn.plugin = function(userConfig){  
  3.      userConfig = $.extend({  
  4.          content: 'Hello user!'  
  5.      }, userConfig);  
  6.      return this.html(useConfig.content);  
  7.  }); 

——翻译结束——
2011-03-07 19:40:37