1

什么是接口

接口是父类要求子类实现的方法,但是父类并不规定子类应该如何实现。例如,我有一个Person父类,定义了一个job的接口。然后定义一个Student类继承Person这个父类。他在就一定要定义job这个函数。

接口之利

在面向对象的编程中接口有一定的自我描述性。并能促进代码的重用。接口可以告诉要使用他的程序员这个类实现了哪些方法。一个程序员为类写下了接口,第二个程序员就只要实现了接口,就可以方便大的项目的解耦。也可以实现依赖倒转原则

接口之弊

JS并没有提供接口的内置语法,因为JS是动态编译的。其他实现接口的语言如C++,JAVA都是在编译过程中实现对接口的校验。JS没有这个过程,要实现接口的校验一定会带来性能上的影响。

《javascript设计模式》的一个例子

var Interface = function(name, methods) {
    if(arguments.length != 2) {
        throw new Error("Interface constructor called with " + arguments.length + "arguments, but expected exactly 2.");
    }
    
    this.name = name;
    this.methods = [];
    for(var i = 0, len = methods.length; i < len; i++) {
        if(typeof methods[i] !== 'string') {
            throw new Error("Interface constructor expects method names to be " + "passed in as a string.");
        }
        this.methods.push(methods[i]);        
    }    
};    

// Static class method.

Interface.ensureImplements = function(object) {
    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];
        if(interface.constructor !== Interface) {
            throw new Error("Function Interface.ensureImplements expects 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];
            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('DynamicMap', ['centerOnPoint', 'zoom', 'draw']);

function displayRoute(mapInstance) {
    Interface.ensureImplements(mapInstace, DynamicMap);
    mapInstance.centerOnPoint(12, 34);
    mapInstance.zoom(5);
    mapInstance.draw();
    ...
}

以上是书中的实现方法。

可以看到每次在使用前都会做一次接口的遍历这样会大大影响效率。而且这个有一定的强制性影响了JS代码的灵活性。我试着做了另一种方法来做到接口的提示作用。并减少强制性。

我的方法

var Interface = function (object, methods) {
  for (var i = 0, len = methods.length; i < len; i++) {
    if (typeof methods[i] !== 'string') {
      throw new Error('Interface constructor expects method names to be passed in as a string.');
    }
    object[methods[i]] = function () {
      throw new Error(this.constructor.name + ' Interface function is undefined');
    };
  }
};
function Person(name) {
  this.name = name;
  this.sayjob = function () {
    console.log('say');
    this.job();
  };
  this.sayage = function () {
    console.log('say');
    this.age();
  };
}
function creatPerson(name) {
  var object = new Person(name);
  Interface(object, ['job', 'age']);
  return object;
}
function Student(name) {
  this.__proto__ = creatPerson(name);
  this.job = function () {
    console.log('job is student');
  };
}
function creatStudent(name) {
  var object = new Student(name);
  return object;
}
var b = creatStudent('b');
b.job();
//b.age();
b.sayjob();
//b.sayage();

总结

我使用了JS的原型来实现,当接口函数被调用时候查看按照JS的运行原理当子类没有实现时候会调用父类中的方法弹出错误并给出提示。我认为接口的主要目的是做限制,不过在JS这种灵活度特别高的语言中,我个人认为这样的限制影响了性能。也带损失了灵活性。所以我把他修改为这种方式实现,已达到代码中给提示的目的来实现接口的个设计模式。


zchq88
634 声望95 粉丝