zoukankan      html  css  js  c++  java
  • JavaScript实现接口的三种经典方式

    接口:提供一种说明一个对象应该有哪些方法的手段

    JavaScript中有三种方式实现接口:

    (1)注释描述接口

    (2)属性检测接口

    (3)鸭式辨型接口

    1、注释描述接口:不推荐

    优点:易于实现,不需要额外的类或函数。

    缺点:纯文档约束,程序不能检查实现接口的对象是否实现了所有接口方法

     1 /**
     2  * interface Composite{
     3  *         function a();
     4  *         function b();
     5  * }
     6  */
     7 // CompositeImpl implements Composite
     8 var CompositeImpl = function(){
     9     //业务逻辑
    10 };
    11 CompositeImpl.prototype.a = function(){
    12     //业务逻辑
    13 };
    14 CompositeImpl.prototype.b = function(){
    15     //业务逻辑
    16 };

    2、属性检测接口:不推荐

    第二种方法要更严谨一点。所有类都明确地声明自己实现了哪些接口,那些想与这些类打交道的对象可以针对这些声明进行检查。那些接口自身仍然只是注释,但现在你可以通过检查一个属性得知某个类自称实现了什么接口。

    优点:能够检查实现了哪些接口

    缺点:并未确保类真正实现了自称实现的接口。你只知道它是否说自己实现了接口。

     1 var interfacesImpl = function(){
     2     //在实现类内部用一个数组保存要实现的方法名
     3     //通常这个属性名是团队中规定好的
     4     //声明自己实现了这两个方法,但实际上并不一定
     5     this.implementsInterfaces = ["Composite","FormItem"];
     6 };
     7 
     8 //专门为这个实现对象写一个检测函数,传入实例对象,用于检查实例对象是否实现了所有接口
     9 function checkImplements(obj){
    10     //调用检查方法 obj是否实现了两个接口,如果没有都实现则抛出异常
    11     if(!isImplements(obj,"Composite","FormItem")){
    12         throw new Error("接口没有全部实现!");
    13     }
    14     //obj是要检查的对象
    15     function isImplements(obj){
    16         //传入的第0个参数是要检查的对象,所以从1开始检查
    17         for(var i=1; i<arguments.length; i++){
    18             //接收接口中每个接口的名字
    19             var interfaceName = arguments[i];
    20             //默认未实现该接口
    21             var foundFlag = false;
    22             //循环查询传入实例对象的实现接口数组,检查是否全部实现
    23             for(var j=0; j<obj.implementsInterfaces.length; j++){
    24                 //如果实现了这个接口,就修改标记并跳出
    25                 //debugger
    26                 if(obj.implementsInterfaces[j] == interfaceName){
    27                     foundFlag = true;
    28                     break;
    29                 }
    30             }
    31             //如果遍历实现接口数组之后没找到,返回false
    32             if(!foundFlag){
    33                 return false;
    34             }
    35         }
    36         return true;
    37     }
    38 }
    39 
    40 //使用实例对象并检测
    41 var o = new interfacesImpl();
    42 checkImplements(o);

    3、鸭式辨型法:推荐

    背后的观点:如果对象具有与接口定义的方法同名的所有方法,那么久可以认为它实现了这个接口。

     1 /**
     2  * 接口类
     3  *
     4  * @param {String} name  接口的名字
     5  * @param {Array} methods   要实现方法名称的数组
     6  */
     7 var Interface = function (name, methods) {
     8     //判断参数个数
     9     if(arguments.length !== 2){
    10         throw new Error("接口构造器参数必须是两个!");
    11     }
    12     this.name = name;
    13     this.methods = [];
    14     for(var i=0; i<methods.length; i++){
    15         if(typeof methods[i] !== "string"){
    16             throw new Error("接口实现的函数名称必须是字符串!");
    17         }
    18         this.methods.push(methods[i]);
    19     }
    20 }
    21 
    22 //实例化接口对象---传入接口名和要实现的方法数组
    23 var CompositeInterface = new Interface("CompositeInterface",["add","remove"]);
    24 var FormItemInterface = new Interface("FormItemInterface",["update","select"]);
    25 
    26 //实现接口的类
    27 var CompositeImpl = function(){
    28 
    29 }
    30 
    31 //实现接口的方法
    32 CompositeImpl.prototype.add = function(obj){
    33     //...
    34 }
    35 CompositeImpl.prototype.remove = function(obj){
    36     //...
    37 }
    38 CompositeImpl.prototype.select = function(obj){
    39     //...
    40 }
    41 //在这里少实现一个方法,下面检查是否全部实现了接口
    42 // CompositeImpl.prototype.update = function(obj){
    43 //     //...
    44 // }
    45 
    46 //实例化 实现接口的对象
    47 var c = new CompositeImpl();
    48 
    49 //检验接口里的方法是否全部实现,如果不通过则抛出异常
    50 Interface.ensureImplements = function(obj){
    51     //如果接收到参数小于2,说明异常
    52     if(arguments.length < 2){
    53         throw new Error("接口检查方法的参数必须多余两个!");
    54     }
    55     //接口实现检查
    56     for(var i=0,len = arguments.length; i<len; i++){
    57         //获取当前接口
    58         var instanceInterface = arguments[i];
    59         //判断接收到的是不是接口的对象,如果不是则抛出异常
    60         if(instanceInterface.constructor !== Interface){
    61             throw new Error("接口检测函数必须传入接口对象!");
    62         }
    63         //检查实例化接口的对象是不是实现了接口里的所有方法
    64         for(var j=0; j<instanceInterface.methods.length; j++){
    65             //接收到的字符串方法
    66             var methodName = instanceInterface.methods[j];
    67             //如果obj里面没有methodsName这个方法,或者有这个属性但是不是函数,就抛出异常
    68             if(!obj[methodName] || typeof obj[methodName] !== "function"){
    69                 throw new Error("接口方法" + methodName + "没有实现!");
    70             }
    71         }
    72     }
    73 }
    74 
    75 //传入要检查的类,和要实现的所有接口对象
    76 Interface.ensureImplements(c, CompositeInterface, FormItemInterface);
    77 c.add();
  • 相关阅读:
    spring 使用 context:property-placeholder 加载 多个 properties
    Spring自动注入Bean
    正则查询符合条件的字符串
    csv测试类。用起来,就是那么简单。每个单元格都是以逗号分隔
    eclipse 设置字体高亮
    订单生成类,个人经验总结!
    java 导出Excel 大数据量,自己经验总结!
    Oracle的数据恢复——Flashback用法汇总
    org.apache.log4j.Logger详解
    Date、String和Timestamp类型转换
  • 原文地址:https://www.cnblogs.com/haishen/p/10731037.html
Copyright © 2011-2022 走看看