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+" 定義的不一致");就會拋出異常。

為什么使用接口

  • 在大型項目中,有利於團隊協作(比如分工等)
  • 降低代碼的耦合度,從某種意義上講使代碼更加靈活
  • 提高開發效率,通過接口的定義可以先“用上”接口,等接口被實現之后即可得到驗證,而不需要進行等待


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM