zoukankan      html  css  js  c++  java
  • JavaScript使用接口

    在经典的Java面向对象语言中,可以用关键字interface来定义接口,用implement来实现接口,而JavaScript虽然也是面向对象语言,但是它并没有内置这些,不过由于JavaScript的灵活性,我们可以通过模拟来实现,方法是使用一个辅助类和辅助函数来协助完成这一过程。

    代码

    先把例子写出来,后面再讲解一些细节:

    // 辅助类
    var Interface = function(name,methods){
      if(arguments.length != 2){
        throw new Error("参数数量不对,期望传入两个参数,但是只传入了"+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("期望传入的方法名是以字符串的格式类型,而不是"+ (typeof methods[i]) + "类型");
        }
        this.methods.push(methods[i]);
      }
    }
    
    // 辅助函数
    Interface.ensureImplements = function(object){
    
      if(arguments.length < 2){
        throw new Error("期望传入至少两个参数,这里仅传入"+arguments.length+"个参数");
      }
      for(var i = 1; i < arguments.length; i++){
        var interface = arguments[i];
        if(!(interface instanceof Interface)){
          throw new Error(arguments[i] + "不是一个接口");
        }
        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("对象的方法 "+method+" 与接口 "+interface.name+" 定义的不一致");
          }
        }
      }
    }
    
    //接口
    var RobotMouth = new Interface('RobotMouth',['eat','speakChinese','speakEnglish']);
    var RobotEar = new Interface('RobotEar',['listen']);
    
    // 实现RobotMouth、RobotEar接口
    // 构造函数
    var Robot = function(){
    }; 
    
    Robot.prototype = {
    
      // 实现RobotMouth接口
      eat: function(){
        console.log("I can eat");
      },
      speakChinese: function(){
        console.log("I can speak Chinese");
      },
      speakEnglish: function(){
        console.log("I can speak English");
      },
    
      // 实现RobotEar接口
      listen: function(){
        console.log("I can listening");
      }
    };
    
    var miniRobot = new Robot();
    
    function useRobot(robot){
      Interface.ensureImplements(miniRobot,RobotMouth,RobotEar);
      robot.eat();
      robot.listen();
    }
    
    useRobot(miniRobot);
    

    运行结果:

    I can eat  
    I can listening
    

    下面对这段代码进行讲解:

    定义接口

    //接口
    var RobotMouth = new Interface('RobotMouth',['eat','speakChinese','speakEnglish']);
    var RobotEar = new Interface('RobotEar',['listen']);
    

    我们定义了两个接口,通过new Interface()来定义接口,在Interface这个函数中:

    • 第一个参数是接口名称
    • 第二个参数是一个数组,数组是元素是字符串的格式,里面分别是接口定义的方法

    上述的代码,可理解为做下面的这样的定义:

    /*
    interface RobotMouth(){
      function eat();
      function speakChinese();
      function speakEnglish();
    }
    
    interface RobotEar(){
      function listen();
    }
    */
    

    现在我们来看一下Interface() 这个构造函数:

    // 辅助类
    var Interface = function(name,methods){
      if(arguments.length != 2){
        throw new Error("参数数量不对,期望传入两个参数,但是只传入了"+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("期望传入的方法名是以字符串的格式类型,而不是"+ (typeof methods[i]) + "类型");
        }
        this.methods.push(methods[i]);
      }
    }
    

    这个构造函数实现的是对传入的参数进行严格的校验,如果参数不对就会报错。这里首先是判断参数的个数,第二是判断传入的方法名是否是字符串的格式。

    接口的实现

    接口定义好后,通过一个类来实现,这里要注意的是,需要给出明确的注释,说明这个类实现的是哪个接口。

    // 实现RobotMouth、RobotEar接口
    // 构造函数
    var Robot = function(){
    }; 
    
    Robot.prototype = {
    
      // 实现RobotMouth接口
      eat: function(){
        console.log("I can eat");
      },
      speakChinese: function(){
        console.log("I can speak Chinese");
      },
      speakEnglish: function(){
        console.log("I can speak English");
      },
    
      // 实现RobotEar接口
      listen: function(){
        console.log("I can listening");
      }
    };
    

    这里我们定义了一个Robot构造函数来实现以上两个接口,方法写在原型上,注意注释明确。

    使用接口

    var miniRobot = new Robot();
    
    function useRobot(robot){  
      Interface.ensureImplements(miniRobot,RobotMouth,RobotEar);
      robot.eat();
      robot.listen();
    }
    
    useRobot(miniRobot);
    

    首先我们创建了一个实例叫miniRobot,然后做为参数传入useRobot() 这个函数进行生产调用,在这个函数里的第一行代码Interface.ensureImplements(miniRobot,RobotMouth,RobotEar); 是对传入的miniRobot进行严格的校验,校验不通过会抛出异常。它接受的参数必须大于等于两个:

    • 第一个参数是一个实现了接口的对象
    • 第二个参数是对象的一个接口
    • 第三个参数同上(若存在的话)

    我们来看一下这段代码:

    // 辅助函数
    Interface.ensureImplements = function(object){
    
      if(arguments.length < 2){
        throw new Error("期望传入至少两个参数,这里仅传入"+arguments.length+"个参数");
      }
      for(var i = 1; i < arguments.length; i++){
        var interface = arguments[i];
        if(!(interface instanceof Interface)){
          throw new Error(arguments[i] + "不是一个接口");
        }
        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("对象的方法 "+method+" 与接口 "+interface.name+" 定义的不一致");
          }
        }
      }
    }
    

    首先对传入的参数进行校验,必须传入两个或以上的参数。
    然后检查每个传入的接口是否已经定义,如果未定义,就抛出异常,表示不是一个接口。
    然后对每个接口定义的方法进行遍历,与第一个参数(实现接口的对象)进行比较,如果对象没有实现接口的方法,那么这段代码throw new Error("对象的方法 "+method+" 与接口 "+interface.name+" 定义的不一致");就会抛出异常。

    为什么使用接口

    • 在大型项目中,有利于团队协作(比如分工等)
    • 降低代码的耦合度,从某种意义上讲使代码更加灵活
    • 提高开发效率,通过接口的定义可以先“用上”接口,等接口被实现之后即可得到验证,而不需要进行等待
  • 相关阅读:
    Debian 9/Ubuntu 18添加rc.local开机自启的方法
    第一次使用Debian9所遇到的问题
    Open-Falcon注册时点击Sign up按钮没反应
    使用VMware虚拟机里的Ubuntu18.04部署RAID 10磁盘阵列
    Ubuntu18.04下Ansible的基本使用
    Go语言求水仙花数(for循环)
    自研模块加载器(四) 模块资源定位-异步加载
    自研模块加载器(三) module模块构造器设计-模块数据初始化
    自研模块加载器(二) 加载器结构与设计导论
    自研模块加载器(一) 模块系统概述与自定义模块规范书写规定
  • 原文地址:https://www.cnblogs.com/hlwyfeng/p/6099957.html
Copyright © 2011-2022 走看看