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

  • 相关阅读:
    Qt编写数据可视化大屏界面电子看板4-布局另存
    Qt编写数据可视化大屏界面电子看板3-新建布局
    Qt编写数据可视化大屏界面电子看板2-配色方案
    Qt编写数据可视化大屏界面电子看板1-布局方案
    Qt编写自定义控件19-图片背景时钟
    Qt编写自定义控件18-魔法小鱼
    AngularJS概述-3D
    controller与requestmapping
    Maven pom.xml 报 Missing artifact jdk.tools:jdk.tools:jar:1.7
    大数据究竟是什么
  • 原文地址:https://www.cnblogs.com/Langzi127/p/2677035.html
Copyright © 2011-2022 走看看