JavaScript設計模式: 接口模仿

JavaScript中模仿接口有三種方法數組

1. 註釋法函數

/*
interface Composite(){
    function add(child);
    function remove(child);
    function getChild(index);
}
interface FormItem(){
    function save();
}
*/

  缺點:沒法確保真正實現接口中的方法集,也不會拋出錯誤以告知用戶程序中有問題,對測試和調試沒有什麼幫助。它主要屬於程序文檔範疇,在這種作法中,對接口約定的遵照徹底依靠自覺。測試

  優勢:不須要額外的類或函數,不影響文件尺寸或執行速度,由於所用的註釋能夠在對代碼進行部署時予以剔除ui

2. 屬性檢查this

  類經過增長一個implementsInterfaces的數組屬性來顯式本身支持什麼接口,任何一個要求其參數屬於特定類型的函數均可以對這個屬性進行檢查,並在所需接口未在聲明這列時拋出一個錯誤。  spa

var CompositeForm=function(id, method, action){
    this.implementsInterfaces=['Composite','FormItem'];
}
function addForm(formInstance){
    if(!implements(formInstance, 'Composite', 'FormItem')){
        throw new Error('Object does not implements a required interface');
    }
}
function implements(object){
    for(var i=1;i<arguments.length;i++){
        var interfaceName=arguments[i];
        var interfaceFound=false;
        for(var j=0;j<object.implementsInterfaces.length;j++){
            if(object.implementsInterfaces[j]==interfaceName){
                interfaceFound=true;
                break;
            }
        }
        if(!interfaceFound){
            return false;
        }
    }
    return true;
}

  優勢:對類所實現的接口提供了文檔說明。若是須要的接口不在一個類所聲明的接口列表中,你會看到錯誤消息。調試

  缺點:不能確保真正實現了自稱實現的接口。你只知道它是否說本身實現了接口。在建立一個類時聲明它實現了一個接口,但後來在實現該接口所規定的方法時卻漏掉其中的某一個,這種錯誤很常見。此時全部檢查都能經過,但所需的方法卻不存在,這將在代碼中埋下隱患。code

3. 鴨辨型法orm

  "像鴨子同樣走路而且嘎嘎叫的就是鴨子"。類是否聲明本身支持哪些接口並和重要,只要它具備這些接口中的方法就行。若是對象具備與接口定義的方法同名的全部方法,那麼就能夠認爲它實現了這個接口。對象

var Composite=new Interface('Composite', ['add','remove','getChild']);
var FormItem=new Interface('FormItem', ['save']);
var CompositeForm=function(id, method, action){
    
}
function addForm(formInstance){
    Interface.ensureImplements(formInstance, Composite, FormItem);
}
var Interface=function(name, methods){
    if(arguments.length!=2){
        throw new Error("Interface constructor called with "+arguments.length+ " arguments, but expected exactly 2.")
    }
    this.name=name;
    this.methods=[];
    for(var i=0, len=methods.length;i<len;i++){
        if(typeof methods[i]!=='string'){
            throw new Error('Interface constructor expects method names to be passed in as a string');
        }
        this.methods.push(methods[i]);
    }
}
Interface.ensureImplements=function(object){
    if(arguments.length<2){
        throw new Error('Function Interface.ensureImplements called with '+arguments.length+' arguments, but expected at least 2.');
    }
    for(var i=1, len=arguments.length;i<len;i++){
        var interface=arguments[i];
        if(arguments.constructor!=Interface){
            throw new Error('Function Interface.ensureImplements expected arguments two and above to be instances of Interface.');
        }
        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('Function Interface.ensureImplements: object does not implement the '+interface.name+' interface.Method '+method+' was not found.');
            }
        }
    }
}

  缺點:類並不聲明本身實現了哪些接口,這下降了代碼的可重用性,而且也缺少其餘兩種方法那樣的自我描述性。它須要使用一個輔助類(Interface)和一個輔助函數(ensureImplements),它只關心方法的名稱,並不檢查參數的名稱、數目或類型。

相關文章
相關標籤/搜索