zoukankan      html  css  js  c++  java
  • Javascript中如何实现interface机制

    我们知道,ECMAScript中是没有interface一说的。虽然如此,参考《Pro Javascript Design Pattern》一书,哥算是找到方案了。

    最简单的方案,就是通过文档说明了。简称方案1,代码如下:

    /*
    interface composite{
        function add(child);
        function remove(child);
        function getChild(index);
    }

    interface formItem{
        function save();
    }
    */

    var compositeForm = function (id, name) {
        this.id = id;
        this.name = name;

        if (typeof (compositeForm._initialized) === "undefined") {
            // implement the composite interface.
            compositeForm.prototype.add = function (child) {
                console.log("added.");
            };
            compositeForm.prototype.remove = function (child) {
                console.log("removed.");
            };
            compositeForm.prototype.getChild = function (index) {
                return "Here is a child.";
            };

            // implement the formItem interface.
            compositeForm.prototype.save = function () {
                console.log("saved.");
            };

            compositeForm._initialized = true;
        }

    }; 

    这种方案里,通过js的伪代码,定义好composite和formItem 2个接口,然后在 compositeForm 类中通过动态原型来实现接口中定义的方法。以下是简单的几行测试代码: 

    var item = new compositeForm(1, "form 1");
    console.log(item.id);
    item.add(null);
    item.save();

    var item2 = new compositeForm(2, "form 2");

    console.log(item.add == item2.add); 


    对于具有特强执行力和完全可控制的团队来说,完全没有问题。问题是,21世纪有这样的团队吗?即便有,IT圈里的人员变动也不能保证它一如既往啊。改进的方案就是,通过约定和校验了。作出改进(简称方案2),详细如下: 

    /*
    interface composite{
        function add(child);
        function remove(child);
        function getChild(index);
    }

    interface formItem{
        function save();
    }
    */

    var compositeForm = function (id, name) {
        this.id = id;
        this.name = name;

        if (typeof (compositeForm._initalized) === "undefined") {
            // implement the composite interface.
            compositeForm.prototype.add = function (child) {
                console.log("added.");
            };
            compositeForm.prototype.remove = function (child) {
                console.log("removed.");
            };
            compositeForm.prototype.getChild = function (index) {
                return "Here is a child.";
            };

            // implement the formItem interface.
            compositeForm.prototype.save = function () {
                console.log("saved.");
            };

            //sign for implemented interfaces
            compositeForm.prototype.implementsInterfaces = ["composite", "formItem"];

            compositeForm._initalized = true;
        }
    };

    function implements(obj, interfaces) {
        if (obj == null || typeof (obj) !== "object") {
            throw new Error("obj must to be a object.");
        }
        if(interfaces == null || !(interfaces instanceof Array)){
            throw new Error("interfaces must to be a Array");
        }
        for(item in interfaces){
            if(typeof(interfaces[item]) !== "string"){
                throw new Error("interfaces must to be a string Array");
            }
        }

        var result = true;
        if (interfaces.length > 0) {
            if (typeof (obj.implementsInterfaces) === "undefined" || !(obj.implementsInterfaces instanceof Array) || obj.implementsInterfaces.length < 1) {
                result = false;
            } else {
                for (item in interfaces) {
                    var itemResult = false;
                    for (funIndex in obj.implementsInterfaces) {
                        if (interfaces[item] == obj.implementsInterfaces[funIndex]) {
                            itemResult = true;
                            break;
                        }
                    }
                    if (!itemResult) {
                        result = false;
                        break;
                    }
                }
            }
        }
        return result;    
    }

    // Validate instace. If invalid, throw exception.
    function addForm(formInstance) {
        if (!implements(formInstance, ["composite", "formItem"])) {
            throw new Error("Object doesn't implement the interfaces.");
        }

        //...

    它的核心就是:compositeForm.prototype.implementsInterfaces = ["composite", "formItem"];通过定义implementsInterfaces属性,并将它赋值为已实现的接口名称的数组。而implements方法就是通过对比对象实体的implementsInterfaces属性和需要实现的接口名称逐一进行对比,来判断实体所属类是否真的实现了指定接口。但是,如果给implementsInterfaces赋值说已实现了某接口,但是并没有实现它的方法,怎么办?


         继续改进,有方案3

    /*
    interface composite{
        function add(child);
        function remove(child);
        function getChild(index);
    }

    interface formItem{
        function save();
    }
    */

    // interface class
    var Interface = function (name, methods) {
        if (arguments.length != 2) {
            throw new Error("Interface constructor called with " + arguments.length + "arguments, but expected exactly 2.");
        }
        if (typeof name !== "string") {
            throw new Error("Interface constructor expected name to be passed in as a string.");
        }
        if (methods == null || !(methods instanceof Array)) {
            throw new Error("Interface constructor expected methods to be passed in as a method.");
        }

        this.name = name;
        this.methods = methods;
    };
    Interface.ensureImplements = function (classFun, interfaces) {
        if (arguments.length != 2) {
            throw new Error("Function Interface.ensureImplements called with " + arguments.length + "arguments, but expected 2.");
        }
        if (classFun == null || typeof (classFun) != "object") {
            throw new Error("classFun expected to be passed in a object.");
        }
        if (interfaces == null || !(interfaces instanceof Array)) {
            throw new Error("interfaces expected to be passed in a Array.");
        }
        for (index in interfaces) {
            if (!(interfaces[index] instanceof Interface)) {
                throw new Error("interfaces[" + index + "] expected to be passed in a Interface.");
            }
            var currentInterface = interfaces[index];
            for (methodIndex in currentInterface.methods) {
                var methodName = currentInterface.methods[methodIndex];
                if (!classFun[methodName] || typeof (classFun[methodName]) != "function") {
                    return false;
                }
            }
        }

        return true;
    };

    // define two interfaces
    var compsite = new Interface("compsite", ["add", "remove", "getChild"]);
    var formItem = new Interface("formItem", ["save"]);

    // a class implements above two interfaces
    var compositeForm = function (id, name) {
        this.id = id;
        this.name = name;

        if (typeof (compositeForm._initialized) === "undefined") {
            // implement the composite interface.
            compositeForm.prototype.add = function (child) {
                console.log("added.");
            };
            compositeForm.prototype.remove = function (child) {
                console.log("removed.");
            };
            compositeForm.prototype.getChild = function (index) {
                return "Here is a child.";
            };

            // implement the formItem interface.
            compositeForm.prototype.save = function () {
                console.log("saved.");
            };

            compositeForm._initialized = true;
        }
    };

    // Validate instace. If valid, alert true. Else, throw exception. 
    function addForm(formInstance) {
        if (!Interface.ensureImplements(formInstance, [compsite, formItem])) {
            throw new Error("Object doesn't implement the interfaces.");
        }

        //...
        alert('true');
    }

    这里定义了Interface类,并实现了类的ensureImplements静态方法。关于Interface类的实现,可以独立作为一个文件,以后多个地方可以用到。然后,通过下面的代码来定义接口: 

    var compsite = new Interface("compsite", ["add", "remove", "getChild"]);
    var formItem = new Interface("formItem", ["save"]);

    至于compositeForm类自身的实现,除了不再需要implementsInterfaces签名,其他和之前的几乎一样。使用时,通过调用: 

        if (!Interface.ensureImplements(formInstance, [compsite, formItem])) {
            throw new Error("Object doesn't implement the interfaces.");

        } 

    来判断是否真的实现了指定接口。它不仅可以判断到接口,还可以判断到方法。 


         至此,不仅可以定义interface,还可以ensure implement了。 (注:以上方法主题思路来源于Pro Javascript Design Pattern,但同时修复了它里面的一些细小问题) 完整代码download

  • 相关阅读:
    self 和 super 关键字
    NSString类
    函数和对象方法的区别
    求两个数是否互质及最大公约数
    TJU Problem 1644 Reverse Text
    TJU Problem 2520 Quicksum
    TJU Problem 2101 Bullseye
    TJU Problem 2548 Celebrity jeopardy
    poj 2586 Y2K Accounting Bug
    poj 2109 Power of Cryptography
  • 原文地址:https://www.cnblogs.com/Langzi127/p/2677035.html
Copyright © 2011-2022 走看看