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,无疑会使程序员间的合作开发更便捷。

      

  • 相关阅读:
    sublime & atom 插件
    正则表达式必知必会读书笔记
    前端自动化工具
    CSS3效果收集
    JS 常用功能收集
    【1】Hover 效果收集
    javascript进阶高手必备知识
    ionic 实现仿苹果手机通讯录搜索功能
    ionic2APP 如何处理返回键问题
    三张图搞懂JavaScript的原型对象与原型链
  • 原文地址:https://www.cnblogs.com/Iwillknow/p/3679148.html
Copyright © 2011-2022 走看看