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

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_32588349/article/details/51629421

在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);

实际使用中可以结合第一种方式一起使用

猜你喜欢

转载自blog.csdn.net/qq_32588349/article/details/51629421