《javascript设计模式》-2-接口

/**
 * 接口是一种指定对象应该有哪些方法的技术,他不关心方法如何实现。
 * 基于接口编程的好处是:实现相同接口的对象,可以互换,而不影响功能实现。
 * 接口还有利于大项目中,多人合作的交流
 */
/**************** 在js中模仿接口 ******************/

//用注释描述接口
//效果最差,不会提供错误信息
//易于实现
/*
 interface Composite {
 function add(child);
 function remove(child);
 function getChild(index);
 }
 interface FormItem {
 function save();
 */

var CompositeForm = function (id, method, action) {
    //implements Composite, FormItem
};

//implement the Composite interface
CompositeForm.prototype.add = function (child) {

};
CompositeForm.prototype.remove = function (child) {

};
Composite.prototype.getChild = function (index) {

};

//implement the formItem interface
CompositeForm.prototype.save = function () {

};


//用属性检查模仿接口
/*
 优点:
 对类所实现的接口提供了文档说明
 如果没有必须的接口会提示错误消息
 缺点:
 显示声明类所支持的接口,但没有真正检测接口是否存在
 */
/*
 interface COMposite {
 function add(child);
 function remove(child);
 function getChild(index);
 }
 interface FormItem {
 function save();
 }
 */
var CompositeForm = function (id, method, action) {
    //add interface into array
    this.implementsInterfaces = ['Composite', 'FormItem'];
    //...
};

function addForm(formInstance) {
    if (!implements(formInstance, 'Composite', 'formItem')) {
        throw new Error('Object does not implement a required interface.');
    }
    //...
}

//The implement function,which checks to see if an object declares that
//it implements the required interface
function implements(object) {
    //looping through all arguments after the first one
    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) {
            //an interface was not found
            return false;
        }
    }
    //all interface were found
    return true;
}


//用鸭式辩型模仿接口
//如果对象具有与接口定义的方法同名的所有方法
//那么就可以认为它实现了这个接口
/**
 * 三种方法中最有用的一种
 * 缺点:
 *     类并不声明自己实现了那些接口,降低了代码的可重用性
 *     缺乏自我描述
 *     不检查方法的参数
 */
//Interface.
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var FormItem = new Interface('FormItem', ['save']);

//CompositeForm class
var CompositeForm = function (id, method, action) {
    //...
};
//...
function addForm(formInstance) {
    ensureImplements(formInstance, Composite, FormItem);
    //this function will throw an error if a required method is not implemented
    //...
}


//本书采用的接口实现方法
//结合第一种和第三种方法
//interfaces
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var formItem = new Interface('FormItem', ['save']);

//CompositeForm class
var CompositeForm = function (id, method, action) {
    //...
};
//...

function addForm(formInstance) {
    Interface.ensureImplements(formInstance, Composite, FormItem);
    //this function will throw an error if a required method is not implemented
    //halting execution of the function
    //all code beneath this line will be executed only if the checks pass
    //...
}


/************ Interface类 *************/
//Constructor
var Interface = function (name, method) {
    // 检测参数个数
    if (arguments.length != 2) {
        throw new Error('Interface constructor called with ' + arguments.length + 'arguments,ut expected exactly 2.');
    }
    this.name = name;
    this.methods = [];
    //遍历方法
    for (var i = 0, len = method.length; i < len; i++) {
        //检查数组值是否字符串
        //如果不是,抛出错误信息
        if (typeof method[i] !== 'string') {
            throw new Error('Interface constructor expects method names to be passed in as a string');
        }
        //将方法名添加到属性数组中
        this.methods.push(method[i]);
    }

};

//static class method
Interface.ensureImplements = function (object) {
    //参数个数必须大于等于2个
    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];
        //如果不是Interface的实例,则抛出错误
        if (interface.constructor !== Interface) {
            throw new Error('Function interface.ensureImplements expectes 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];
            //如果object没有实例中的方法,则抛出错误
            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.');
            }
        }
    }
};


//使用
    var DynamicMap = new Interface('DybamicMap', ['centerOnPoint', 'zoom', 'draw']);

    function displayRoute(mapInstance) {
        Interface.ensureImplements(mapInstance, DynamicMap);
        mapInstance.centerOnPoint(12, 34);
        mapInstance.zoom(5);
        mapInstance.draw();
        //...
    }
    var Test = function () {

    };
    Test.prototype = {
        centerOnPoint:function (a, b) {
            console.log('centerOnPoint2');
        },
        zoom:function (num) {
            console.log('zoom2');
        },
        draw:function(){

        }
    };
    var a = new Test();
    displayRoute(a);


//实例
// ResultFormatter class,before we implement interface checking
//未使用Interface类检测
var TestResult = function () {

};
TestResult.prototype = {
    getDate:function () {

    },
    getResults:function () {

    }
};
var ResultFormatter = function (resultsObject) {
    // 是否为TestResult的实例
    // 不是就抛出错误
    if (!(resultsObject instanceof TestResult)) {
        throw new Error('ResultsFormatter: constructor requires an instance of TestResult as an 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 = 'Test Results from ' + dateOfTest.toUTCString();
    resultsContainer.appendChild(resultsHeader);

    var resultsList = document.createElement('ul');
    resultsContainer.appendChild(resultsList);
    for (var i = 0, len = resultsArray.length; i < len; i++) {
        var listItem = document.createElement('li');
        listItem.innerHTML = resultsArray[i];
        resultsList.appendChild(listItem);
    }

    //返回创建的DOM
    return resultsContainer;
};
/*
 TestResult类可能被修改,致使其不再拥有getDate()方法
 检查仍能通过,但renderResults方法却会失灵
 不允许其他类的实例作为参数
 */

//使用Interface类后
//ResultSet interface
var ResultSet = new Interface('ResultSet', ['getDate', 'getResults']);

//ResultFormatter class, after adding Interface checking
var ResultFormatter = function (resultsObject) {
    Interface.ensureImplements(resultsObject, ResultSet);
    this.resultsObject = resultsObject;
};

ResultFormatter.prototype.renderResults=function(){
    //...
};

  

posted @ 2012-12-16 13:14  LukeLin  阅读(252)  评论(0编辑  收藏  举报