JS设计模式---2.接口

2018-12-08  本文已影响10人  念丶凉

什么是接口

接口提供了一种用以说明一个对象应该具有哪些方法的手段。

接口之利

接口之弊

模仿接口实现

/*
  interface Composite {
     function add(child);
     function remove(child);
     function getChild(child);
  }
   interface FormItem {
     function save(child);
  }
*/
var CompositeFrom = function(id,method,action){
   ...
};
CompositeFrom .prototype.add = function(child){
 ...
};
CompositeFrom .prototype.remove= function(child){
 ...
};
CompositeFrom .prototype.getChild= function(child){
 ...
};
CompositeFrom .prototype.save= function(child){
 ...
};

这种做法易于实现,不需要额外的类或函数。可以提高代码的可重用性。

它的缺点在于没有为确保CompositeFrom真正实现了的正确方法而进行检查,也不会抛出错误告诉程序员程序中有问题,所以对于测试和调试也没有什么帮助。

/*
  interface Composite {
     function add(child);
     function remove(child);
     function getChild(child);
  }
   interface FormItem {
     function save(child);
  }
*/
var CompositeFrom = function(id,method,action){
  //定义一个数组  存放将要实现的接口
  this.implementsInterface = ['Composite','FormItem'];
  ...
};
function addForm(formInstance){
  // 调用检查函数 如果存在未定义的接口 抛出错误
  if(!implements(formInstance,'Composite','FormItem')){
    throw new Error('Object does not implement a required interface')
  }
  ...
}
function implements(object){
  for (var i = 1;i<argumements.length;i++){
    // 遍历参数  跳过第一个 
    var interfaceName = argument[i]; //接口名称
    var interfaceFound = false ; //flag
    for (var j=0;j<object.implementsInterface.length;j++){
      // 遍历存放接口名称的数组
      if(implementsInterface[j] == interfaceName){
        interfaceFound = true;
        break;
      }
    }
    //  如果找到返回true  否则返回false
    return interfaceFound 
  }
}

这种方法不仅对所实现的接口进行了注释说明,如果需要的接口不在一个类所宣称支持接口之内,它还会抛出一个错误,这样就可以强迫其它程序员声明这些接口。

它的缺点在于你不能保证所声明的接口是否真正实现。所以会存在检查通过,而方法不存在的问题。

// Interface
var Composite = new Interface('Composite',['add','remove','getChild']);
var FormItem= new Interface('FormItem',['save']);
//CompositeForm 类
var CompositeForm= function(id,method,action){
 ...
};
functiom addForm(formIntance){
  // 辅助函数  如果引入未定义的接口会抛出错误
  ensureImplements(formIntance,Composite,FormItem);
  ...
}

这种方法不依赖于注释。其各个方面都是可以强制实施的。ensureImplements函数至少需要两个参数,第一个参数是想要检查的对象,其余参数是据以对那个对象进行检查的接口。

它的缺点在于,类并不声明自己实现了哪些接口,降低了代码的可重用性,也缺乏上面两种方法的自我描述性。它依赖于辅助类Interface和辅助函数ensureImplements。

Interface类的实现

// 构造函数

 var Interface = function(name,methods){
    if(arguments.length != 2){  
      throw new Error(`Interface constructor called with ${arguments.length} arguments, but expcted 2.`);
    }
    this.name = name;
    this.methods = [];
    for(var i =0;i<methods.length;i++){
      if(typeof methodsp[i] !== 'string'){
        throw new Error("Interface  constructor expects method name to be passed in as a string");
      } 
      this.methods.push(methods[i]);
    }
};
// 辅助函数
Interface.ensureImplements = function(object){
    //  如果参数小于2个抛出错误
    if(arguments.length<2){
      throw new Error(`Function Interface.ensureImplements called with ${arguments.length} arguments, but expected at least 2.`);
    }
    for(var i = 1; i<arguments.length; i++){
      var interface = arguments[i];
      // 如果类的构造函数不是Interface 抛出错误
      if(interface.constructor !== Interface){
        throw new Error("Function Interface.ensureImplements expects arguments two and above to be insterface of Interface")
      }
       // 遍历存放接口名称的数组
      for (var j=0;j<interface.methods.length;j++){
        var method = interface.methods[j]
        if(!object[method] || typeof method !== 'function'){
          throw new Error(`Function Interface.ensureImplements: object does not implement the ${interface.name} interface.Method ${method} was not found`)
        }
      }
    }
}


上一篇下一篇

猜你喜欢

热点阅读