本章简要介绍了接口在面向对象编程的作用,好处。以及在javascirp中的接口的利弊。同时介绍了javacript中实现接口的方法。
接口是面向对象javascript程序员的工具箱中最有用的工具之一。Gof在书中提到,面向对象设计的第一条原则就是:“针对接口编程而不是实现编程”。
然而javascript本身没有内置的创建或实现接口的方法。也就说javascript本身是没有接口的。不过、由于javascript有强大的灵活性,最终我们可以在javascript中模拟实现接口。
接口提供了一种用来说明一个对象应该具有的哪些方法的手段,它可以表明这些方法的语义,但是不规定这些方法的具体实现。呵呵感觉不怎么专业,很拗口呀。
先讲好处:
1、接口能促进代码重用
2、可以稳定不用类之间的通信方式
3、方便测试和调试
坏处:
1、接口强化了类型的作用,降低了javascript语言的灵活性。
2、javascript 没有原生的接口支持
3、javascript模仿接口带来性能的影响
4、javascript不能强制其他程序员遵守你的接口定义(这个要靠行政手段,呵呵)
其他语言基本使用了interface和implements关键字,内置支持。
1、用注释描述接口
用注释模仿接口是最简单的方法,就是在注释里面写上接口的定义信息。这个超级简单,但效果就不怎么地了。
例子如下:
/** //这里是接口的描述 interface XXXInterFace{ function add(child); function remove(child); } */ var XXXClass=function(){//implements XXXInterFace 说明实现了接口 } XXXClass.prototype.add=function(){ ...... } XXXClass.prototype.remove=function(){ ...... }
2、用属性检查模仿接口
这个方法比第一个要严谨一些。所有的类必须明确的声明自己实现的接口。虽然接口依旧是注释,但是你可以检查某个属性得知实现了什么样的接口。
/** //这里是依旧是接口的描述 interface XXXInterFace{ function add(child); function remove(child); } */ var XXXClass-function(){ this.implementsInterfaces=["XXXInterFace"];//申明实现的接口 } XXXClass.prototype.add=function(){ ...... } XXXClass.prototype.remove=function(){ ...... } //调用类的方法 function dosome(xxxClassInstance){ if(!implements(xxxClassInstance,"XXXInterFace")){//检查实现的接口 alert("没有实现 XXXInterFace") } } function implements(obj){//检查实现的接口的方法 ...... }
3、鸭式辨型模仿接口
鸭式辨型(鸭子测试DUCK TEST)——像鸭子一样走路并且嘎嘎叫的就是鸭子。呵呵这个很有意思,书上说的,这个是james Whitcomb Riley的名言。大家都知道这个大神不?我google了一下,并在前面的连接上加上了基维百科的连接。
言归正传,这个方法比较前面来说,不用借助于注释,而且可以强制实施,但是多了辅助的工具类InterFace和一个辅助函数ensureImplements。
//定义申明接口 var XXXInterFace=new InterFace("XXXInterFace",["add","remove"]); //调用方法 function doSome(instance){ ensureImplements(instance,XXXInterFace);//接口检查 }
4、本书的接口实现,Interface类
书中使用了第一中和第三种的结合,也就是我既写好了注释告诉你我实现的接口,也用到了鸭子辨型的接口检查。呵呵也就是要我们要是用接口的话,也可以模仿这样来实现。还有就是提醒大家注意好好写写注释。
书中具体的InterFace类如下:
// Constructor.呵呵抄不下去了网上下了源代码 var Interface = function(name, methods) { if(arguments.length != 2) { throw new Error("Interface constructor called with " + arguments.length + "arguments, but expected exactly 2."); } this.name = name; this.methods = []; for(var i = 0, len = methods.length; i < len; i++) { if(typeof methods[i] !== 'string') { throw new Error("Interface constructor expects method names to be " + "passed in as a string."); } this.methods.push(methods[i]); } }; // Static class method. Interface.ensureImplements = function(object) { if(arguments.length < 2) { throw new Error("Function Interface.ensureImplements called with " + arguments.length + "arguments, but expected at least 2."); } for(var i = 1, len = arguments.length; i < len; i++) { var interface = arguments[i]; if(interface.constructor !== Interface) { throw new Error("Function Interface.ensureImplements expects arguments " + "two and above to be instances of Interface."); } for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) { var method = interface.methods[j]; if(!object[method] || typeof object[method] !== 'function') { throw new Error("Function Interface.ensureImplements: object " + "does not implement the " + interface.name + " interface. Method " + method + " was not found."); } } } };
工厂模式
组合模式
装饰者模式
命令模式