JS设计模式之接口

JS能把类模仿得惟妙惟肖,也可以模仿接口,参考pro javascript design pattern一书,主要有3种方式

注释(Comment)

这种不用多说了,就是在注释里写明接口定义了哪些方法,哪些地方需要实现什么接口。好处是不会增加任何多的对象或函数,也不会影响执行效率。坏处也很明显,一切靠自觉,而且没有错误提示。

属性检查(Attribute Checking)

function Dog() {
    this.implementInterfaces = ['Animal'];
}

function play(dog) {
    implement(dog, 'Animal');
    dog.eat();
    dog.run();
}

function implement(obj) {
    var interfaceName, interfaceFound, i, j, len;
    for (i = 1; i < arguments.length; i += 1) {
        interfaceName = arguments[i];
        interfaceFound = false;
        for (j = 0, len = obj.implementInterfaces.length; j < len; j += 1) {
            if (interfaceName == obj.implementInterfaces[j]) {
                interfaceFound = true;
                break;
            }
        }
        if (!interfaceFound) {
            throw new Error(interfaceName + " was not implemented");
        }
    }
}

这种方式的好处是有错误提示,但是仍然要靠自觉,即使检查通过了,也不能确保就真的实现了接口的方法。

Duck Typing

function Interface(name, methods) {
    var i, len;

    if (arguments.length !== 2) {
        throw new Error("exactly 2 arguments are expected");
    }

    this.name = name;
    this.methods = [];

    for (i = 0, len = methods.length; i < len; i += 1) {
        if (typeof methods[i] !== 'string') {
            throw new Error("method name is expected to be passed in as a string");
        }
        this.methods.push(methods[i]);
    }
}

Interface.ensureImplements = function (obj) {
    var i, j, interface, method, l,
        len = arguments.length;

    if (len < 2) {
        throw new Error("at least 2 arguments are expected");
    }

    for (i = 1; i < len; i += 1) {
        interface = arguments[i];
        if (interface.constructor !== Interface) {
            throw new Error("instances of Interface are expected");
        }

        for (j = 0, l = interface.methods.length; j < l; j += 1) {
            method = interface.methods[j];
            if (typeof obj[method] !== 'function') {
                throw new Error("Method " + method + "() of Interface " + interface.name + " was not found");
            }
        }
    }
};

var Animal = new Interface('Animal', ['eat', 'run']),
dog = new Dog(); Interface.ensureImplements(dog
, Animal);

"If it walks like a duck and quacks like a duck, it's a duck",这个方法不去管类有没有实现接口,而是把注意力放在实例上,毕竟接口里的方法最后都要落在实例上,只要确保实例含有同名方法,就认为它实现了接口,这也是duck type命名的由来。

接口的实现并不复杂,重要的是恰当的判断是否需要使用接口。

原文地址:https://www.cnblogs.com/coiorz/p/4811569.html