zoukankan      html  css  js  c++  java
  • 深入js的面向对象学习篇——温故知新(一)

      在学习设计模式前必须要知道和掌握的***。

      为类添加新方法:

    Function.prototype.method = function(name,fn) {
        this.prototype[name] = fn;
    }
    
    //改进版:支持链式调用
    
    Function.prototype.method = function(name,fn) {
        this.prototype[name] = fn;
        return this;
    }

      函数是一等对象,可以存储在变量中,可以作为参数传给其他函数,可以作为返回值从其他函数传出,还可以再运行的时候进行构造。这正是用以构造传统面向对象框架的基础。

      对象具有易变性。类方法可以在类实例创建之后再添加,实例仍然能够获得新添加的方法。个人觉得,这也是对象扩展的威力源泉。

      一、接口

      “针对接口,而不是实现编程”

      接口提供了一种用以说明一个对象应该具备哪些方法的手段。既定的一批接口具有自我描述性,并能促进代码的重用。接口可以告诉程序员一个类实现了哪些方法,从而帮助其使用这个类。接口最实在的用途是什么?~一个程序员可以针对所需要的类定义一个接口,并转交给另一个程序员。第二个程序员可以随心所欲地编写自己的代码,只要他定义的类实现了那个接口就行。

      当然接口也有弊端。比如额外的方法调用的开销无法避免。

      而接口使用中的最大问题在于,无法强迫其他程序员遵守你定义的接口。不像其它语言(像java等,编译期间会因为接口继承后没有写实现而报错),javascript中必须用手工的办法保证某个类实现了一个接口(你可能对此不理解是什么意思,稍安,等下立马解释^_^)。如果项目的其他程序员不认真对待接口,那么这些接口的使用是无法得到强制性保证的。除非项目的所有人都同意使用接口并对其进行检查,否则接口的很多价值都无从体现。

      解惑的时候到了,为什么前文说“javascript中必须用手工的办法保证某个类实现了一个接口”。事实上,javascript没有interface和implements关键字,也不在运行时对接口约定是否得到遵守进行检查。我们只能在javascript中模仿接口。一下介绍模仿接口的三种方法:注释法、属性检查法、鸭式辨型法。

      ① 注释法:

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

      这种方法易于实现,但是不会提供错误信息。

      ② 用属性检查模仿接口

    /*
    interface Composite {
        function add(child);
        function remove(child);
        function getChild(index); 
    }
    
    interface FormItem {
        function sava();  
    }
    */
    
    var compositeForm = function(id,method,action) {
        this.implementInterfaces = ['Composite','FormItem'];
       ......  
    };
    
    function addForm(formInstance) {
        if(!implements(formInstance,'Composite','FormItem')) {
            throw new Error("Object does not implement a required interface.");
        ....
        }
    }
    
    function implement(object) {   //检查接口是否被实现
        for(var i = 0;i < arguments.length;i++) {
            var interfaceName = arguments[i];
            var interfaceFound = false;
            for(var j = 0;j < object.implementsInterfaces.length;j++) {
                if(interfaceName == object.implementsInterfaces[j]) {
                    interfaceFound = true;
                    break;
                }
            } 
            if(!interfaceFound) {
                return false;
            }
        }
        return true;
    }

      优点:它对所有实现的接口提供了文档说明。如果需要的接口不在一个类宣称支持的接口之列,你会看到错误消息。通过利用这些错误,你可以强迫其它程序员声明这些接口。

      缺点:它并未确保类真正实现自称实现的接口。很可能,只是有了这个接口的实现声明,方法体忘记写了,一个空的方法体造成了假象。

      ③ 用鸭式辨型模仿接口

      思想:类是否声明自己支持哪些接口不重要,只要它具有这些接口中的方法就行。“像鸭子一样走路并且嘎嘎叫的就是鸭子”。如果一个对象具有与接口定义的方法同名的所有方法,那么就可以认为它实现了这个接口。(个人觉得,这有点像客户端检测机制,我们不是去判断浏览器的类型,而是转而判断浏览器是否支持此项功能^_^换个角度思考问题往往有事半功倍之效。)

      缺点:类并不声明自己实现了哪些接口,这降低了代码的可重用性,并且也缺乏其他两种方法的自我描述性。

      

      个人觉得,最好的就接口实现时方法一和方法三的结合。也就是可读性和保证性相结合。

    var Composite = new Interface('Composite',['add','remove','getChild']);
    var FormItem = new Interface('FormItem',['save']);
    
    var CompositeForm = function(id,method,action) {
        ....
    };
    
    function addForm(formInstance) {
            Interface.ensureImplements(formInstance,Composite,FormItem);
        ....
    }
    
    var Interface = function(name,methods) {
        if(arguments.length != 2) {
            throw new Error("...........");
        }
        
        this.name = name;
        this.methods = [];
        for(var i = 0;i < methods.length;i++) {
            if(typeof methods[i] !== 'string') {
                throw new Error("..........");
            }
            this.methods.push(methods[i]);
        }
    };
    
    Interface.ensureImplements = function() {
        if(arguments.length < 2) {
            throw new Error("....");
        }
    
        for(var i = 1,len = arguments.length;i < len;i++) {
            var interface = arguments[i];
            if(interface.constructor !== Interface) {
                throw new Error("....");
            }
    
            for(var j = 0,methodsLen = interface.methods.length;j < methodsLen;j++) {
                var method = interface.methods[j];
                if(!object[method]||typeof object[method] !== 'function') {
                    throw new Error("....");
                }
            }
        }
    }

      接口在运用设计模式实现复杂系统的时候最能体现其价值。降低了对象间的耦合程度。在大型项目中,易于程序员的合作,如果你知道测试中的桩测试,你对此用个空方法体进行占位,提供API,无疑会使程序员间的合作开发更便捷。

      

  • 相关阅读:
    Python 存储引擎 数据类型 主键
    Python 数据库
    Python 线程池进程池 异步回调 协程 IO模型
    Python GIL锁 死锁 递归锁 event事件 信号量
    Python 进程间通信 线程
    Python 计算机发展史 多道技术 进程 守护进程 孤儿和僵尸进程 互斥锁
    Python 异常及处理 文件上传事例 UDP socketserver模块
    Python socket 粘包问题 报头
    Django基础,Day7
    Django基础,Day6
  • 原文地址:https://www.cnblogs.com/Iwillknow/p/3679148.html
Copyright © 2011-2022 走看看