您的位置:首页 > Web前端 > JavaScript

JavaScript-设计模式之接口的实现

2016-06-11 00:23 465 查看
在JS中,并没有真正意义上的接口,我们只能通过模拟的方式实现接口的效果,使用接口可以促进代码的重用,降低代码之间的耦合度,减少代码错误及查找错误原因,坏处就是加大代码量,而且并不能强制程序员实现接口。JS中模拟接口的方式有三种。

第一种:注释的方式

这种方式是使用注释显示的告诉程序员需要实现哪些接口,这种方式完全靠程序员的自觉性,并且是否真正实现了接口并不能检查,对代码的调试不起任何帮助,相反正因为这种方式,不会对代码性能产生影响。

/**
* 基于注释的实现-接口代码在注释中,对于程序不起任何作用,仅仅是写给程序员看。
*
* 这是一个GAME接口,具备一个playGames方法
*public interface Game {
*      public void playGames();
* }
*
*
* 这是一个Food接口,具备一个eat方法
* public interface Food {
*      public void eat();
* }
*/
var Person = function(name) {
this.name = name;
};
//根据注释的内容,自觉地实现接口中的方法
Person.prototype.playGames = function() {
alert(this.name + "在打游戏!")
};
Person.prototype.eat = function() {
alert(this.name + "在吃饭!")
};
//创建对象p
var p = new Person("小明");
//调用方法
p.playGames();


第二种:使用属性检查是否实现接口

这种方式是第一种方式的扩展,在对象的属性中声明需要实现的接口名,然后设计方式去检测该对象是否实现了指定接口,这种方式缺点很明显,并没有办法检测是否真正实现了接口中的方法。

/**
* 基于注释的实现-接口代码在注释中,对于程序不起任何作用,仅仅是写给程序员看。
*
* 这是一个GAME接口,具备一个playGames方法
*public interface Game {
*      public void playGames();
* }
*
*
* 这是一个Food接口,具备一个eat方法
* public interface Food {
*      public void eat();
* }
*/
var Person = function(name) {
//通过属性的方式,声明一个属性,值为需要实现的接口名
this.implInterfaces = ["Game","Food"];
this.name = name;
};
//根据注释的内容,自觉地实现接口中的方法
Person.prototype.playGames = function() {
alert(this.name + "在打游戏!")
};
Person.prototype.eat = function() {
alert(this.name + "在吃饭!")
};
//创建对象p
var p = new Person("小明");
//调用方法
p.playGames();

//定义一个方法用于检测Person对象的类是否实现指定的接口
function checkPerson(person) {
//调用公共的方法进行判断,如果返回false,表示没有实现接口,抛出错误
if(!checkImplements(person,"Fightable","Walkable")) throw new Error("必须实现Fightable和Walkable俩个接口");
};
//定义一个公共方法用于检测一个对象的类是否实现指定的接口
function checkImplements(obj) {
//如果这个对象不具备接口属性,说明没有实现接口,抛出错误
if(!obj.implInterfaces) throw new Error("必须声明所实现的接口");
//每一个方法中都存在一个对象arguments来存储传递进来的实际参数
//arguments包含对象本身以及参数字符串,因此遍历要从下标1开始,跳过对象本身
for(var i = 1; i < arguments.length; i++) {
if(typeof arguments[i] != "string") throw new Error(arguments[i] + "的类型不正确");
var found =false;
for(var j = 0; j < obj.implInterfaces.length; j++) {
var inter = obj.implInterfaces[j];
//检测实现的接口是否正确
if(inter == arguments[i]) {
found = true;
break;
}
}
if(!found) return false;
}
return true;
};
//检查对象p所在的类是否实现了接口
checkPerson(p);


第三种:鸭式辨型方式

鸭式辨型(这个名称来自James Whitomb Riley的名言:“像鸭子一样走路并且嘎嘎叫的就是鸭子”),意思就是说,判断一个方法是否实现了接口,只需要看这个方法中是否包含接口中的所有方法,如果包含了,我们就可以认为这个方法实现了此接口。

1、首先定义一个用于创建接口的函数

//定义一个接口方法,参数为长度为2的数组,数组第一个元素为对象接口对象,第二个元素为接口方法的数组
var Interface = function(name) {
//arguments为实际传进来的参数
if(arguments.length != 2) throw new Error("创建的接口不符合标准,必须有俩个参数,第二个参数是接口的方法");
this.name = name;
this.methods = [];
//获取方法数组
var methods = arguments[1];
for(var i = 1; i < methods.length; i++) {
this.methods.push(methods[i]);
}
};


2、使用如上函数声明2个接口并创建对象实现接口方法

//声明俩个接口及接口的方法
var Game = new Interface("Game",["playGames"]);
var Food = new Interface("Food",["eat","throwFood"]);
var Person = function(name) {
this.name = name;
};
//实现接口的三个方法
Person.prototype.playGames = function() {
alert(this.name + "在打游戏!");
};
Person.prototype.eat = function() {
alert(this.name + "在吃饭!");
};
Person.prototype.throwFood = function() {
alert(this.name + "丢掉食物");
};
//创建对象p
var p = new Person("小明");


3、编写方法检测对象是否实现接口的方法

//用于检测对象是否实现了接口的方法,参数为数组,第一个元素为对象,其余元素为实现的接口对象
Interface.checkImplements = function(obj) {
if(arguments.length < 2) throw new Error("要检查的接口必须传入接口对象的参数,参数的个数必须大于等于2");
for(var i = 1; i < arguments.length; i++) {
var intObj = arguments[i];
if(intObj.constructor != Interface) throw new Error(intObj + "接口的对象不正确");
//检查方法是否符合要求
var cmethods = intObj.methods;
for(var j =0; j < cmethods.length; j++) {
if(!obj[cmethods[j]] || typeof obj[cmethods[j]] != "function") throw new Error("必须实现:" + cmethods[j] + "这个方法");
}
}
}


4、检测对象是否实现的指定接口对象中的方法

function checkPerson(person) {
//调用检测方法,传入要检测的对象及其需要实现的接口对象
Interface.checkImplements(person,Game,Food);
};
//检测对象p是否实现了接口
checkPerson(p);


实际使用中可以结合第一种方式一起使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息