01.Javascript中的接口----Interface [转载]
转载地址:http://blog.csdn.net/ymmc001/archive/2010/11/05/5990021.aspx
本文主要讲述如何用原生的Javascript代码来模拟并实现接口
前言
众所周知,在Java、C#等语言中,接口由专门的关键字interface来定义,而接口的实现则有implements关键字来完成,接口有什么特点呢?简单地说有(不完全归纳):
- 不可被实例化
- 所有方法都是抽象方法
- 所有属性都是public static final的
但是在Javascript语言中,没有现成的关键字可以直接用来定义一个接口,也没有现成的关键字可以直接用来实现所谓的extends和implements。既然没有现成的,下面将阐述如何用原生的Javascript代码来模拟并实现接口。
Javascript中的接口
接口的定义
/** * Interface构造器 * @param {String} name 接口名 * @param {Array} methods 接口中的抽象方法 * @exception {Error} 参数不合格时抛出异常 * @example * var IActionListener = new Interface("IActionListener",["method1","method2"]); */ var Interface = function(name, methods) { if(arguments.length != 2) { throw new Error("Interface有且只有两个参数,而当前参数个数为:" + arguments.length ); } this.name = name; this.methods = []; for(var i = 0, len = methods.length; i < len; i++) { if(typeof methods[i] !== 'string') { throw new Error("Interface中的方法名必须合法"); } this.methods.push(methods[i]); } };
这个Interface类是用来模仿Java中的interface关键字的,但不同的是,Java中通过interface IActionListener{}的形式来定义一个接口,而这里则是通过var IActionListener = new Interface("IActionListener",["method1"])的形式来定义。
这个接口类接受两个参数,第一个表示需要定义的接口名称,第二个参数表示该接口中即将声明的抽象方法。该类在产生新接口的时候,会检查参数的合法性,只要通过检查,接口便产生了,同时具有两个属性:接口名和方法列表。
接口的实现
/** * 接口实现的检查,保证object是InterfaceN的实例 * @param {Object} oInterface 待检查的接口实例 * @param {Class} InterfaceN 被实现的Interface * @exception {Error} 参数不合格时抛出异常 * @example * Interface.ensureImplements(oActionListener,IActionListener); */ Interface.ensureImplements = function(oInterface,Interface1,Interface2,InterfaceN) { if(arguments.length < 2) { throw new Error("Interface.ensureImplements方法至少需要两个参数,而当前参数个数为:" + arguments.length); } for(var i = 1, len = arguments.length; i < len; i++) { var interface = arguments[i]; if(interface.constructor !== Interface) { throw new Error(interface + "不是Interface的实例,不是接口"); } for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) { var method = interface.methods[j]; if(!oInterface[method] || typeof oInterface[method] !== 'function') { throw new Error("所给参数没有实现" + interface.name + "接口," + method + "未找到"); } } } };
这个静态方法是用来模仿Java中的implements关键字的,但不同的是,Java中通过class ActionListener implements IActionListener{}来实现的,而这里则是通过interface.ensureImplements(oActionListener,IActionListener)的形式来保证的。
这个静态方法接受两个参数,第一个表示接口实现类的实例对象,第二个参数表示接口实现类(当然了,这里其实是一个对象)。方法的内部会校验实例对象是否都实现了接口中的所有抽象方法,如果在该实例中存在没有被实现的抽象方法(方法未找到),则表明该实例对象不是接口实现类的实例对象。
接口实例的创建与使用
//创建接口 var IActionListener = new Interface("IActionListener",["method1","method2"]); //接口实例的创建 var oActionListener = { method1 : function(){ alert("这是方法1"); }, method2 : function(){ alert("这是方法2"); } }; //implements确认 Interface.ensureImplements(oActionListener,IActionListener); //调用实例中的方法 oActionListener.method1();
这是一个简单的接口定义并实现的过程。
在Javascript中,必然存在着很多种接口的模拟方式,这里只是其中的一种实现思路。
模拟之不当,还请见谅。
非常希望您能提出宝贵的意见。
从ensureImplements方法到implements方法的升级(2010-09-22更新)
前面定义的ensureImplements(oInterface,Interface1,Interface2,InterfaceN)是通过实例来保证的,但是按照常理来说,一个接口被实现以后,便可以进行实例化,但是这里不是真正意义上的实现,而是一种检查、一种保证。为了让接口实现后仍然能通过new关键字实例化对象,下面需要将原来的方法进行升级,于是我定义了下面的方法:implements(ImplementsClass,Interface1,Interface2,InterfaceN),代码如下:
/** * 接口的实现 * @param {function} ImplementsClass 待实现的类 * @param {object} InterfaceN 被实现的Interface,Interface的实例 * @exception {Error} 参数不合格时抛出异常 * @example * implements(ActionListener,IActionListener); */ var implements = function(ImplementsClass,Interface1,Interface2,InterfaceN){ if(arguments.length < 2) { throw new Error("Interface.ensureImplements方法至少需要两个参数,而当前参数个数为:" + arguments.length); } //保证ImplementsClass的类型为function if(typeof arguments[0] !== "function"){ throw new Error("实现类的类型必须为function"); } for(var i = 1, len = arguments.length; i < len; i++) { var interface = arguments[i]; if(interface.constructor !== Interface) { throw new Error(interface + "不是Interface的实例,不是接口"); } //这里循环进行接口抽象方法的实现 for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) { var method = interface.methods[j]; if(!arguments[0].prototype[method]){ arguments[0].prototype[method] = function(){}; } } } }
经过这样的升级,我们的代码就可以写成这样了:
//创建接口 var IActionListener = new Interface("IActionListener",["method1","method2"]); //创建实现类 var ActionListener = function(){}; //实现 implements(ActionListener,IActionListener); //这个时候,ActionListener.prototype已经是如下这个样子了: /* ActionListener.prototype = { method1 : function(){}, method2 : function(){} }; */ //接下来可以真正的填充被空实现的方法的逻辑了 ActionListener.prototype = { method1 : function(){ alert("这是方法1"); }, method2 : function(){ alert("这是方法2"); } }; //调用实例中的方法 oActionListener.method1();
OK,一切正常。到此为止,在后续的文章中提到的implements方法,就是这个方法了,请务必留意,谢谢。