rwson

rwson

一个前端开发

javascript接口

接口:

接口是提供了一种用以说明一个对象应该具有哪些方法的手段,但它并不规定这些方法应该如何实现。在JS中,没有像其他面向对象程序语言的interface关键字,所以实现的方法也语言不同;JS实现接口的主要方式主要为定义描述法、属性检测法和鸭式辨型法,其中鸭式辨型法是目前用的最多的。

1、定义描述法

/**
 *  interface CompsiteImpl{
 *      function add();
 *      function remove();
 *      function update();
 *  }
 */

/**
 * 实现接口
 * @constructor
 */
function CompsiteImpl(){
}

CompsiteImpl.prototype = {
    "constructor":CompsiteImpl,
    "add":function(){
        console.log("我是add方法!");
    },
    "remove":function(){
        console.log("我是remove方法!");
    },
    "update":function(){
        console.log("我是update方法!");
    }
};

此方法也称注释法,顾名思义,就是通过一系列的注释来定义该类需要实现哪些接口方法,这是最简单定义接口的一种方法。但是此方法缺点实在太明显了,比如一个人代码写完了,他只能通过肉眼来判断是不是都把刚才注释里面的方法都实现了;他哪天代码做修改了,是否和注释一致等等的。只是属于一个类似于帮助文档的范畴,太死板。

2、属性检测法

/**
 *  interface Compsite{
 *      function add();
 *      function remove();
 *      function update();
 *  }
 *
 *  interface FormItem{
 *      function select();
 *  }
 *
 */

//  实现接口
//  需要实现 Compsite FormItem
function CompsiteImpl(){
    //  在类的内部定义一个变量
    this.implementsInterface = ["Compsite","FormItem"];
}

CompsiteImpl.prototype = {
    "constructor":CompsiteImpl,
    "add":function(){
        console.log("add 方法");
    },
    "remove":function(){
		console.log("remove 方法");
	},
    "update":function(){
		console.log("remove 方法");},
    "select":function(){
		console.log("select 方法");
	}
};

/**
 *
 * @param instance
 *
 * 检测类的方法
 */
function checkCompsiteImpl(instance){
    //  判断当前对象是否实现了所有的接口
    if(!isImplements(instance,"Compsite","FormItem"))
	{
        throw new Error("object does not implement 
			a required interface");
    }
}

/**
 *
 * @param object
 *
 * 公共的、具体的检测方法(核心方法)
 */
function isImplements(object){
    for(var i = 1,l = arguments.length;
	i < l;i ++){
        var interfaceName = arguments[i],
            interfaceFound = false;
        for(var j = 0,
			len = object.implementsInterface.length;
		j < len;j ++)
		{
            if(object.implementsInterface[j] ==
		 interfaceName){
                interfaceFound = true;
            }
        }
        if(!interfaceFound){
            return false;
        }
        return true;
    }
}

var c1 = new CompsiteImpl();
checkCompsiteImpl(c1);
c1.add();

这种方法相对来说高级一点了,如果有一个接口没有没实现,会看到一个错误,代码不往下继续走了。但缺点在于仍无法判断是否真正实现了对应的接口方法,仅仅只是"自称"实现了接口,同时这种方法耦合性也比较高,放到另外一个地方可能就需要进行修改才能复用。

3、鸭式辨型法

/**
 *
 * @param name      接口名,字符串
 * @param methods   需要实现的方法,接收方法的集合、数组
 * @constructor
 * 接口类
 */
function Interface(name,methods){
    //  判断接口的参数个数
    if(arguments.length != 2){
        throw new Error("this instance interface 
		constructor required 2 arguments!");
    }
    this.name = name;
    this.methods = [];
    //  定义一个空数组,等待接收methods里面的方法名
    for(var i = 0,len = methods.length; i < len; i ++){
        if(typeof methods[i] !== "string"){
            throw new Error("the Instance method name
			 is error!");
        }
        this.methods.push(methods[i]);
    }
}

/**
 *
 * @param object
 *
 * 检验方法,如果通过,不做任何操作,否则抛出异常
 */
Interface.ensureImplement = function(object){
    //  至少得实现一个接口
    if(arguments.length < 2){
        throw new Error("Interface.ensureImplement 
	constructor arguments must be 2 
		or more arguments!");
    }
    //  获得接口实例对象
    for(var i = 1,len = arguments.length;
	i < len;i ++){
        var instanceInterface = arguments[i];
        //  判断参数是否为接口类的
        if(!(instanceInterface instanceof Interface))
		{
            throw new Error("the arguments" + 
			instanceInterface + "is 
			not an instance of Interface Class");
        }
        //  循环接口实例对象里面的每个方法
        for(var j = 0,l = instanceInterface.methods.length;
		 j < l;j ++){
            var methodName = 
			instanceInterface.methods[j];
            //  接收每个方法的名字(字符串)
            if(!arguments[0][methodName] || 
	typeof arguments[0][methodName] !== "function")
	{
                throw new Error("the method "+ 
				methodName +" is not found");
            }
            //  不存在或者不是方法类型
        }
    }
};

//  实例化接口对象
var CompsiteInterface = new Interface("CompsiteInterface",
["add","remove"]),
FormInteInterface = new 
Interface("FormInteInterface",
["update","select"]);

/**
 *
 * @constructor
 * 接口类
 */
function CompsiteImpl(){
}
//  实现接口
CompsiteImpl.prototype = {
    "constructor":CompsiteImpl,
    add:function(){
        console.log("add 方法");
    },
    remove:function(){},
    update:function(){},
    select:function(){}
};

//  检验接口里的方法
var c1 = new CompsiteImpl
(c1,CompsiteInterface,FormInteInterface);

Interface.ensureImplement
(c1,CompsiteInterface,FormInteInterface);

c1.add();

此方法就是目前最经典的一种方法,从上面的代码中可以看出,在这里完全采用的是面向对象的方法,通过实例化两个接口对象来声明需要实现的方法,最后实例化我们真正需要需要实例化的对象c1,通过Interface下的静态方法来判断是否已经实现全部接口,如果有一个没被实现则会看到具体是哪个没被实现,并且终止代码的继续运行,且耦合度较低。

接口的好处主要是提高了系统相似模块的重用性,使得不同类的通信更加稳固。一旦实现接口,则必须实现接口中所有的方法。在大型系统中,接口的益处是显而易见的,但是如果在一个小的web系统中使用接口就显得画蛇添足了。