《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(){

    //...

};

  

你可能感兴趣的:(JavaScript)