日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

JavaScript设计模式 Item 2 -- 接口的实现

發(fā)布時間:2023/12/18 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript设计模式 Item 2 -- 接口的实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1、接口概述

1。什么是接口?

接口是提供了一種用以說明一個對象應該具有哪些方法的手段。盡管它可以表明這些方法的語義,但它并不規(guī)定這些方法應該如何實現(xiàn)。

2. 接口之利

  • 促進代碼的重用。
    接口可以告訴程序員一個類實現(xiàn)了哪些方法,從而幫助其使用這個類。

  • 有助于穩(wěn)定不同類之前的通信方式。

  • 測試和調(diào)式因此也能變得更輕松。
    在javascript這種弱類型語言中,類型不匹配錯誤很難跟蹤。使用接口可以讓這種錯誤的查找變午更容易一點,因為此時如果一個對象不像所要求的類型,或者沒有實現(xiàn)必要的方法,那么你會得到包含有用信息的明確的錯誤提示。這樣一來,邏輯錯誤可以被限制在方法自身,而不是在對象構(gòu)成之中。

  • 接口還能讓代碼變得更穩(wěn)固.
    因為對接口的任何改變在所有實現(xiàn)它的類都必須體現(xiàn)出來。如果接口添加了一個操作,而某個實現(xiàn)它的類并沒有相應的添加這個操作,那么你肯定會立即見到一個錯誤。

3. 接口之弊

javascript是一種具有極強表現(xiàn)圖片的語言,這主要得益于其弱類型的特點。而接口的使用則一定程序上強化了類型的作用。這降低了語言的靈活性。javascript并沒有提供對接口的內(nèi)置支持,而試圖模仿其它語言內(nèi)置的功能總會有一些風險。

js中接口使用的最大問題在于,無法強迫其他程序員遵守你定義的接口。在其它語言中,接口的概念是內(nèi)置的,如果某人定義了實現(xiàn)一個接口的類,那么編譯器會確保該類的確實現(xiàn)了這個接口。而在javascript中則必須用手工的辦法保證某個類實現(xiàn)了一個接口。編碼規(guī)范和輔助類可以提供一些幫助,但無法徹底根除這個問題。如果項目的其他程序員不認真對待接口,那么這些接口的使用是無法得到強制性保證的。除非項目的所有人都同意使用接口并對其進行檢查,否則接口的很多價值都無從體現(xiàn)。

2、在javascript中模仿接口

javascript中模仿接口的三種方法:注解描述法、屬性檢查法、鴨式辨型法。

沒有哪種技術(shù)是完美的,但三者結(jié)合使用基本上可以令人滿意。

1、注釋描述法實現(xiàn)接口

用注釋模仿接口是最簡單的方法,但效果卻是最差的。這種方法模仿其他頁面對象語言中的做法,使用了interface和implements關(guān)鍵字,但把它們放在注釋中,以免引起語法錯誤。如下:

//javascript中定義接口的方式有三種: //1、注解描述的方式/** * interface Composite{ * function add(obj); * function remove(obj); * function update(obj); }優(yōu)點:程序員可以有參考 缺點:缺點一大堆,他只是一個借口的文檔范疇,假如不實現(xiàn)所有的方法,程序照樣可以運行,太松散了。對測試和調(diào)試難度大 */// Implement of interface Composite var CompositeImpl =function(){/*this.add = function(obj){};this.remove = function(obj){};這種函數(shù)定義的方法,在實例化一個對象的時候,new一個示例,將產(chǎn)生一個方法,且各個實力的方法還不一樣。所以采用下面的方法:*/CompositeImpl.prototype.add = function(obj){}CompositeImpl.prototype.remove = function(obj){} CompositeImpl.prototype.update = function(obj){} }var c1 = new CompositeImpl(); var c2 = new CompositeImpl()alert(c1.add == c2.add)

這種模仿并不是很好。它沒有為確保Composite真正實現(xiàn)了正確的方法集而進行檢查,也不會拋出錯誤以告知程序員程序中的問題。說到底它主要還是屬于程序文檔范疇。在這種做法中,對接口約定的遵守完全依靠自覺。

2、屬性檢測法實現(xiàn)接口

這種方法更嚴謹一點。所有類都明確地聲明自己實現(xiàn)了哪些接口,那些想與這些類打交道的對象可能針對這些聲明進行檢查。那些接口自身仍然只是注釋,但現(xiàn)在你可以通過檢查一個屬性得知某個類自稱實現(xiàn)了什么接口。

/** * interface Composite{* function add(obj);* function remove(obj);* function update(obj);* }* interface FormItem{* function select(obj);* }*/// CompositeImpl implements interface Composite,FormItemvar CompositeImpl =function(){//顯示在類的內(nèi)部,接收所實現(xiàn)的接口,一般來說,這是一個規(guī)范,// 我們項目經(jīng)理:在內(nèi)部類定義一個數(shù)組,名字要固定this.interfaceImplments = ['Composite','FormItem'];CompositeImpl.prototype.add = function(obj){alert("小平果");}CompositeImpl.prototype.remove = function(obj){} CompositeImpl.prototype.update = function(obj){}/*CompositeImpl.prototype.select = function(obj){}*/}//定義函數(shù)檢測,判斷當前對象是否實現(xiàn)了所有的接口function checkCompositeImpl (instance){if (!isImplments(instance,'Composite','FormItem')) {throw new Error('Object cannot implements all the interface');};}//公用的具體檢測方法(核心方法),主要目的就是判斷示例對象有沒有實現(xiàn)相關(guān)的接口;function isImplments(object){//arguments 對象會的函數(shù)的實際對象for (var i = 1, len = arguments.length; i < len; i++) { //注意這里從1開始,逐個方法判斷。var interfaceName = arguments[i]; //接收實現(xiàn)每一個接口的名字var interfaceFound = false;//判斷此方法到底是實現(xiàn)了還是失敗了?規(guī)范里定義了interfaceImplments.for (var j = 0;j < object.interfaceImplments.length; j++) {if(object.interfaceImplments[j] == interfaceName){interfaceFound = true;break;}};//如果沒有實現(xiàn),則返回falseif (!interfaceFound) {return false;};}return true;}var c1 = new CompositeImpl(); checkCompositeImpl(c1);c1.add();

這個例子中,CompositeImpl 宣稱自己實現(xiàn)了Composite接口,其做法是把這兩個接口名稱加入一個名為implementsInterfaces的數(shù)組。類顯式聲明自己支持什么接口。任何一個要求基于參數(shù)屬于特定類型的函數(shù)都可以對這個屬性進行檢查,并在所需接口未在聲明之列時拋出一個錯誤。

這種方法有幾個優(yōu)點。它對類所實現(xiàn)的接口提供了文檔說明。如果需要的接口不在一個類宣稱支持的接口之列,你會看到錯誤消息。通過利用這些錯誤,你可以強迫其他程序員聲明這些接口。

這種方法的主要缺點在于它并未確保類真正實現(xiàn)了自稱實現(xiàn)的接口。你只知道它是否說自己實現(xiàn)了接口。在創(chuàng)建一個類時聲明它實現(xiàn)了一個接口,但后來在實現(xiàn)該接口所規(guī)定的方法時卻漏掉其中的某一個,這種錯誤很常見。此時所有檢查都能通過,但那個方法卻不存在,這將在代碼中埋下一個隱患。另外顯式聲明類所支持的接口也需要一些額外的工作。

3、鴨式辨型法實現(xiàn)接口

其實,類是否聲明自己支持哪些接口并不重要,只要它具有這些接口中的方法就行。鴨式辨型(這個名稱來自James Whitomb Riley的名言:“像鴨子一樣走路并且嘎嘎叫的就是鴨子”)正是基于這樣的認識。它把對象實現(xiàn)的方法集作作為判斷它是不是某個類的實例的唯一標準。這種技術(shù)在檢查一個類是否實現(xiàn)了某個接口時也可大顯向身手。這種方法背后的觀點很簡單:如果對象具有與接口定義的方法同名的所有方法,那么就可以認為它實現(xiàn)了這個接口。你可以用一個輔助函數(shù)來確保對象具有所有必需的方法:

/* 實現(xiàn)接口的第三種方式:鴨式辨型發(fā)實現(xiàn)接口,(較為完美的實現(xiàn)方法)核心思想:一個類實現(xiàn)接口的主要目的:把其中的方法都實現(xiàn)了(檢測方法)完全面向?qū)ο? 代碼實現(xiàn)統(tǒng)一,實現(xiàn)解耦*///1、接口類---Class Interface ===>實例化N多個接口/***接口類的參數(shù)?幾個* 參數(shù)1:接口名* 參數(shù)2:接收方法的集合(數(shù)組)*/ var Interface = function(name , methods){//判斷接口的參數(shù)個數(shù)if (arguments.length !=2) {throw new Error('the instance interface constructor arguments should be 2');};this.name =name;//this.methods = methods;this.methods = [];for (var i = 0, len = methods.length; i <len; i++) {if (typeof methods[i] !== "string"){throw new Error('the name of method is wrong');}this.methods.push(methods[i]);} }//2、準備工作,具體的實現(xiàn)//(1)實例化接口對象 var CompositeInterface = new Interface('CompositeInterface',['add','delete']); var FormItemInterface = new Interface('FormItemInterface',['update','select']);//(2)具體的實現(xiàn)類 //CompositeImpl implments CompositionIterface FormItemIterface var CompositeImpl = function(){}//(3)實現(xiàn)接口的方法 implements methods CompositeImpl.prototype.add = function(obj){alert("add"); } CompositeImpl.prototype.delete = function(obj){alert("delete"); } CompositeImpl.prototype.update = function(obj){alert("update"); } /*CompositeImpl.prototype.select = function(obj){alert("select"); }*///3、檢驗接口里的方法 //如果檢測通過,不做任何操作;不通過,則拋出異常。 //這個方法的目的就是 檢測方法的Interface.ensureImplements =function(object){//如果接受參數(shù)長度小于2 ,證明還有任何實現(xiàn)的接口if (arguments.length < 2) {throw new Error('The Interface has no implement class');};//獲得接口的實例對象for (var i = 1, len= arguments.length; i < len; i++) {var instanceInterface =arguments[i];//判斷參數(shù)是否為 接口類的類型if (instanceInterface.constructor !==Interface) {throw new Error('The arguments constructor is not Interface Class');};for (var j = 0, len2 =instanceInterface.methods.length ; j <len2; j++ ) {//用一個臨時變量 ,接收每個方法的名字(注意為字符串類型)var methodName = instanceInterface.methods[j];//object[key] 獲得方法if (!object[methodName] || typeof object[methodName] !== 'function'){throw new Error('the method"'+ methodName+'"is not found');}}} }var c1 =new CompositeImpl(); Interface.ensureImplements(c1,CompositeInterface,FormItemInterface); c1.add();

與另外兩種方法不同,這種方法并不借助注釋。其各個方面都是可以強制實施的。ensureImplements函數(shù)需要至少兩個參數(shù)。第一個參數(shù)是想要檢查的對象。其余參數(shù)是據(jù)以對那個對象進行檢查的接口。該函數(shù)檢查其第一個參數(shù)代表的對象是否實現(xiàn)了那些接口所聲明的所有方法。如果發(fā)現(xiàn)漏掉了任何一個方法,它就會拋出錯誤,其中包含了所缺少的那個方法和未被正確實現(xiàn)的接口的名稱等有用信息。這種檢查可以用在代碼中任何需要確保某個對象實現(xiàn)了某個接口的地方。在本例中,addForm函數(shù)僅當一個表單對象支持所有必要的方法時才會對其執(zhí)行添加操作。

盡管鴨式辨型可能是上述三種方法中最有用的一種,但它也有一些缺點。這種方法中,類并不聲明自己實現(xiàn)了哪些接口,這降低了代碼的可重用性,并且也缺乏其他兩種方法那樣的自我描述性。它需要使用一個輔助類Interface和一個輔助函數(shù)ensureImplements。而且,它只關(guān)心方法的名稱,并不檢查其參數(shù)的名稱、數(shù)目或類型。

3、Interface類的使用場合

嚴格的類型檢查并不總是明智的。許多js程序員根本不用接口或它所提供的那種檢查,也照樣一干多年。接口在運用設計模式實現(xiàn)復雜系統(tǒng)的時候最能體現(xiàn)其價值。它看似降低javascript的靈活性,而實際上,因為使用接口可以降低對象間的耦合程度,所以它提高了代碼的靈活性。接口可以讓函數(shù)變得更靈活,因為你既能向函數(shù)傳遞任何類型的參數(shù),又能保證它只會使用那些具有必要方法的對象。

4、Interface類的用法

判斷代碼中使用接口是否劃算是最重要的一步。對于小型的、不太費事的項目來說,接口的好處也許并不明顯,只是徒增其復雜度而已。你需要自行權(quán)衡其利弊。如果認為在項目中使用接口利大于弊,那么可以參照如下使用說明:
1、 將Interface類納入HTML文件。
2、 逐一檢查代碼中所有以對象為參數(shù)的方法。搞清代碼正常運轉(zhuǎn)要求的這些對象參數(shù)具有哪些方法
3、 為你需要的每一個不同的方法集創(chuàng)建一個Interface對象。
4、 剔除所有針對構(gòu)造器顯式檢查。因為我們使用是鴨式辨型,所以對象的類型不再重要。
5、 以Interface.ensureImplements取代原來的構(gòu)造器檢查。

示例
假設你要創(chuàng)建一個類,它可以將一些自動化測試結(jié)果轉(zhuǎn)化為適于在網(wǎng)頁上查看的格式。該類的構(gòu)造器以一個TestResult類的實例為參數(shù)。它會應客戶的請求對這個TestResult對象所封裝的數(shù)據(jù)進行格式化,然后輸出。
原始定義:

var ResultFormatter =function(resultsObject){if(!(resultsObject instanceof TestResult)){throw newError("ResultsFormatter:constructor requires an instance of TestResult asan argument.")}this.resultsObject = resultsObject;}ResultFormatter.prototype.renderResults =function(){var dateOfTest = this.resultsObject.getDate();var resultsArray =this.resultsObject.getResults();var resultsContainer =document.createElement('div');var resultsHeader =document.createElement("h3");resultsHeader.innerHTML = "TestResults from "+dateOfTest.toUTCString();resultsContainer.appendChild(resultsHeader);var resultList =document.createElement("ul");resultsContainer.appendChild(resultList);for(var i=0,len=resultsArray.length;i<len;i++){var listItem=document.createElement('li');listItem.innerHTML =resultsArray[i];resultList.appendChild(listItem);}return resultsContainer;}

該類的構(gòu)造器會對參數(shù)進行檢查,以確保其的確為TestResult類的實例。如果參數(shù)達不到要示,構(gòu)造器將拋出一個錯誤。有了這樣的保證,在編寫renderResults方法時,你就可以認定有g(shù)etDate和getResults這兩個方法可供使用。實際上這并不能保證所需要的方法得到了實現(xiàn)。TestResult類可能會被修改,致使其不再擁有g(shù)etDate()方法。在此情況下,構(gòu)造器中的檢查仍能通過,但renderResults方法卻會失靈。

此外,構(gòu)造器的這個檢查施加了一些不必要的限制。它不允許使用其他類的實例作為參數(shù),哪怕它們原本可以如愿發(fā)揮作用。例如,有一個名為WeatherData在也擁有g(shù)etDate和getResults這兩個方法。它本來可以被ResultFormatter類用得好好的。但是那個顯式類型檢查會阻止使用WeatherData類的任何實例。
問題解決辦法是刪除那個使用instanceOf的檢查,并用接口代替它。首先,我們需要創(chuàng)建這個接口:

//ResultSetInterface. var ResultSet =new Interface(“ResultSet”,[‘getDate’,’getResults’]);

上面的這行代碼創(chuàng)建了一個Interface對象的新實例。第一個參數(shù)是接口的名稱,第二個參數(shù)是一個字符串數(shù)組,其中的每個字符串都是一個必需的方法名稱。有了這個接口之后,就可以用接口檢查替代instanceOf檢查了

var ResultFormatter = function(resultsObject){Interface.ensureImplements(resultsObject,ResultSet);this.resultsObject = resultsObject; } ResultFormatter.prototype.renderResults= function(){… }

renderResults方法保持不變。而構(gòu)造器則被改為使用ensureImplements方法而不是instanceof運算符。現(xiàn)在構(gòu)造器可以接受WeatherData或其他任何實現(xiàn)所需要方法的類的實例。我們只修改了幾行ResultFormatter類代碼,就讓那個檢查變得更準確,而且更寬容。

5、依賴于接口的設計模式

  • 工廠模式
  • 組合模式
  • 裝飾模式
  • 命令模式

版權(quán)聲明:本文為小平果原創(chuàng)文章,轉(zhuǎn)載請注明:http://blog.csdn.net/i10630226

轉(zhuǎn)載于:https://www.cnblogs.com/dingxiaoyue/p/4948175.html

總結(jié)

以上是生活随笔為你收集整理的JavaScript设计模式 Item 2 -- 接口的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。