JavaScript使用介面

来源:http://www.cnblogs.com/hlwyfeng/archive/2016/11/24/6099957.html
-Advertisement-
Play Games

在經典的Java面向對象語言中,可以用關鍵字interface來定義介面,用implement來實現介面,而JavaScript雖然也是面向對象語言,但是它並沒有內置這些,不過由於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+" 定義的不一致");就會拋出異常。

為什麼使用介面

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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • HTTP Status 500 - Wrapper cannot find servlet class com.servlet.servlet.RegServlet or a class it depends on type Exception report message Wrapper cann ...
  • C語言是我們大多數人的編程入門語言,對其也再熟悉不過了,不過很多初學者在學習的過程中難免會出現迷茫,比如:不知道C語言可以開發哪些項目,可以應用在哪些實際的開發中……,這些迷茫也導致了我們在學習的過程中不知道如何學、學什麼,所以,總結這個列表,希望對C語言初學者可以有所幫助~ C語言可以做什麼? 從 ...
  • 什麼是Hibernate? Hibernate是基於ORM(O:對象,R:關係,M:映射)映射的持久層框架,是一個封裝JDBC的輕量級框架,主要實現了對資料庫的CUPD操作。 註:CRUD是指在做計算處理時的增加(Create)、查詢(Retrieve)(重新得到數據)、更新(Update)和刪除( ...
  • 學習這個東西挺奇怪的,時間一長就容易忘記,或者記不清楚。今天看到一些UML圖的關係,發現有些出入了,索性就寫下來,以後再忘記的時候過來看看。 在UML的類圖中,常見的有以下幾種關係: 繼承(Generalization), 實現(Realization), 關聯(Association), 依賴(D ...
  • 今天講單例設計模式,這種設計模式和工廠模式一樣,用的非常非常多,同時單例模式比較容易的一種設計模式。 一、什麼是單例設計模式 單例模式,也叫單子模式,是一種常用的軟體設計模式。在應用這個模式時,單例對象的類必須保證只有一個實例存在。 二、單例模式的技巧 三、單例模式的應用場景 資料庫設計,我們發送一 ...
  • 設計模式;一個程式員對設計模式的理解:“不懂”為什麼要把很簡單的東西搞得那麼複雜。後來隨著軟體開發經驗的增加才開始明白我所看到的“複雜”恰恰就是設計模式的精髓所在,我所理解的“簡單”就是一把鑰匙開一把鎖的模式,目的僅僅是著眼於解決現在的問題,而設計模式的“複雜”就在於它是要構造一個“萬能鑰匙”,目的 ...
  • 原網站:C# Entity Framework併發處理 在軟體開發過程中,併發控制是確保及時糾正由併發操作導致的錯誤的一種機制。從 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NET Entity Framework,.NET 都為併發控制提供好良好的支持方案。併發處理方式一般分 ...
  • 回到目錄 很久就想寫一套屬於自己的消息隊列組件,前段時候看了湯雪華同學的EQueue,感覺還是不錯的,他也是看了rabbitMQ之後寫的Equeue,在設計上與前者有類似的地方,而大叔這次準備寫一個LindQueue,當前整體架構都差不多,無非是生產者,管道,消費者三個角色,而核心部分就是管道Bro ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...