zoukankan      html  css  js  c++  java
  • 01.Javascript中的接口Interface [转载]

    转载地址:http://blog.csdn.net/ymmc001/archive/2010/11/05/5990021.aspx

    本文主要讲述如何用原生的Javascript代码来模拟并实现接口

    前言

    众所周知,在Java、C#等语言中,接口由专门的关键字interface来定义,而接口的实现则有implements关键字来完成,接口有什么特点呢?简单地说有(不完全归纳):

    1. 不可被实例化
    2. 所有方法都是抽象方法
    3. 所有属性都是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方法,就是这个方法了,请务必留意,谢谢。

  • 相关阅读:
    55最佳实践系列:Logging最佳实践
    关于 Multiget hole:spymemcached对此的实现方法
    Java两则故障分析和常见连接超时时间
    spymemcached :某个mc节点操作连续超时超过998次就 AutoReconnect 的特性
    最佳实践系列:前端代码标准和最佳实践
    随手小记:PHPFPM模式下PHP最大执行时间、Pragma和postcheck
    Storm 是如何跟踪一条消息以及它衍生出来的消息都被成功处理的
    Tumblr的消息通知系统是如何构建的
    职业化之可以固化的六个工作模式
    三个实例演示 Java Thread Dump 日志分析
  • 原文地址:https://www.cnblogs.com/jsfans/p/1909349.html
Copyright © 2011-2022 走看看