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

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

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

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

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

/*

  interface Composite{

       function add(child);

    function remove(child);

    function getChild(index);

}

 

interface FormItem{

       function save();

}

*/

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

varCompositeForm=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();

}

*/

 

varCompositeForm=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’)){

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

}

}

 

function implements(object){

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

              varinterfaceName=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、 用鸭式辨型模仿接口。

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

//接口.

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

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

//实现类

varCompositeForm=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 newError("the interface length is bigger than2");       

}       

this.Name =name;       

this.Method =[];       

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

if(typeofmethods[i]!== string) {       

throw newError("the method name is notstring");       

}       

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

}   

}   

 

/* ensureImplement 方法实现*/   

Interface.ensureImplement = function (object){       

if (arguments.length< 2) {           

throw newError("there is not Interface or theinstance");       

}       

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

var interface1 =arguments[i];           

if(interface1.constructor !== Interface){               

throw newError("the argument is notinterface");           

 }           

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 doesntimplement theinterface");                                  

}           

}       

}   

}

 

使用示例:

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

 

functiondisplayRoute(mapInstance){

 Interface.ensureImplements(mapInstance,DynamicMap);

   mapInstance.centerOnPoint(12,34);

   mapInstance.zoom(5);

   mapInstance.draw();

   …

}

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

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

var Man = function (name, age){       

this.Name =name;       

this.Age =age;   

}   

Man.prototype = {

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

GetAge: function () { returnthis.Age; }   

}   

var test = function(instance){              

Interface.ensureImplement(instance,Person);          

var name =instance.GetName();       

alert(name);   

}   

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

 

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

工厂模式

组合模式

装饰者模式

命令模式

会在以后的章节中介绍。

 

完成于2013-01-17  20:54

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值