Javascript设计模式读书笔记二 接口

Javascript 接口;设计模式的经典语录“针对接口而不是类编程”

Javascript是种弱类型语言,类型不匹配错误很难跟踪,使用接口可以让这种错误的查找变得更容易点;接口还可以让逻辑代码变得更稳固,因为接口添加一个操作,类必须实现它。

Javascript接口缺点:在某种程序上增加额外方法调用的开销(可以在开发完成后剔除接口代码);Javascript接口必须用手工的办法保证某个类实现某个接口,编码规范和辅助类可以提供一些帮助,但无法彻底根除这个问题,除非项目组的人员都同意并且强制使用接口并对其检查,否则接口很多价值都无法体现。

1、  在Javascript中模仿接口。使用注释来模仿其它语言的接口做法。代码如下:

/*

  interface Composite{

       function add(child);

    function remove(child);

    function getChild(index);

}

interface FormItem{

       function save();

}

*/

上面的一段注释即为模仿接口,只是人为按照这种方式来实现这种接口。程序并不会真正继承,程序也不会检查错误。实现接口代码如下:

var CompositeForm=function(id,method,action){  //implements Composite,FormItem

   …

};

//实现Composite接口

CompositeForm.prototype.add=function(child){

   …

};

CompositeForm.prototype.remove=function(child){

   …

};

CompositeForm.prototype.getChild=function(index){

   …

};

//实现FormItem接口

CompositeForm.prototype.save=function(){

   …

};

尽管以上如此,只是人为的模仿,但也有其优点。不需要额外的类或函数。可以提高代码的可重用性,因为现在那些类实现的接口都有说明。缺点就是不会提供错误消息,对测试和调试没有帮助。

2、 用属性检查模仿接口。

 这一种方法要更严谨一点。但仍然只是注释,但现在可以通过检查一个属性得知某个类自称实现了什么接口。代码如下:

/*

  interface Composite{

       function add(child);

    function remove(child);

    function getChild(index);

}

interface FormItem{

       function save();

}

*/

var CompositeForm=function(id,method,action){  //implements Composite,FormItem

   this.implementsInterfaces=[‘Composite’,’FormItem’];

};

//实现Composite接口

CompositeForm.prototype.add=function(child){

   …

};

CompositeForm.prototype.remove=function(child){

   …

};

CompositeForm.prototype.getChild=function(index){

   …

};

//实现FormItem接口

CompositeForm.prototype.save=function(){

   …

};

function addForm(formInstance){

   If(!implements(formInstance,’Composite’,’FormItem’)){

              Throw new Error(“Object does not implement a require interface”);

}

}

function implements(object){

   for(var i=1;i<arguments.length;i++){

              var interfaceName=arguments[i];

    var interfaceFound=false;

   for(var j=0;j<object.implementsInterfaces.length;j++){

          if(object.implementsInterfaces[j]==interfaceName){

          interfaceFound=true;

   break;

}

}

if(!interfaceFound){

          return false;

}

}

Return true;

}

     以上这种方法只是模仿接口的改进。可以检查是否实现某个接口,但并不真正的实现。

3、 用鸭式辨型模仿接口。

其实,类是否声明自己支持那些接口并不重要,只要它具有这些接口中的方法就行。把对象实现的方法集作为判断它是不是某个类的实例的唯一标准。这种技术在检查一个类是否实现了某个接口时也大显身手。这就是鸭式辨型模仿接口。可以用一个辅助函数来确保对象具有所有必需的方法。代码如下:

//接口.

var Composite=new Interface(‘Composite’,[‘add’,’remove’,’getChild’]);

var FormItem=new Interface(‘FormItem’,[‘save’]);

//实现类

var CompositeForm=function(id,method,action){         …

};

  ……

  Function addForm(formInstance){

        ensureImplements(formInstance,Composite,FormItem);

    //如果没有实现某个方法这个函数将会抛出一个错误

}

ensureImplements函数至少需要两个参数,每一个是想要检查的对象,其余参数是据以对那个对象进行检查的接口。这种方法需要一个辅助类Interface和一个辅助函数ensureImplements。而且它只关心方法的名称,并不检查其参数的名称、数目或类型。些方式是上述三种方法中最有用的一种。

在现实中,我们可以综合使用第一和第三种方法。即可以提高代码的可重用性及其文档的完善,又可以用辅助类和方法来对对象实现的方法进行显式检查。

Interface 定义代码如下:

var Interface = function (name, methods) {       

if (arguments.length != 2) {           

throw new Error("the interface length is bigger than 2");       

}       

this.Name = name;       

this.Method = [];       

for (var i = 0; i < methods.length; i++) {       

if(typeof methods[i]!== string) {       

throw new Error("the method name is not string");       

}       

this.Method.push(methods[i]);       

}   

}   

/* ensureImplement 方法实现*/   

Interface.ensureImplement = function (object) {       

if (arguments.length < 2) {           

throw new Error("there is not Interface or the instance");       

}       

for (var i = 1; i < arguments.length; i++) {           

var interface1 = arguments[i];           

if (interface1.constructor !== Interface) {               

throw new Error("the argument is not interface");           

 }           

for (var j = 0; j < interface1.Method.length; j++) {               

var method = interface1.Method[j];               

if (!object[method] || typeof object[method] !== function) {                   

 throw new Error("you instance doesnt implement the interface");                                  

}           

}       

}   

}

使用示例:

var DynamicMap=new Interface(‘DynamicMap’,[‘centerOnPoint’,’zoom’,’draw’]);

function displayRoute(mapInstance){

  Interface.ensureImplements(mapInstance,DynamicMap);

   mapInstance.centerOnPoint(12,34);

   mapInstance.zoom(5);

   mapInstance.draw();

   …

}

下面这段代码简要的说明了其使用:

var Person = new Interface("Person", ["GetName", "GetAge"]);     

var Man = function (name, age) {       

this.Name = name;       

this.Age = age;   

}   

Man.prototype = {

GetName: function () { return this.Name; },      // 

GetAge: function () { return this.Age; }   

}   

var test = function (instance) {              

Interface.ensureImplement(instance, Person);          

var name = instance.GetName();       

alert(name);   

}   

test(new Man("Alan",20));
如果我们注释了上面的GetAge方法,在执行的时候就会出错。在ensureImplement的时候发现并没有去实现这个方法。

4、  设计模式中依赖于接口的主要有以下这些。

工厂模式

组合模式

装饰者模式

命令模式

会在以后的章节中介绍。

完成于2013-01-17  20:54

原文地址:https://www.cnblogs.com/webdep/p/2865197.html