zoukankan      html  css  js  c++  java
  • s的封装和信息隐蔽

    ======转自:http://www.douban.com/note/200763868/

    1. 简介:

             封装是面向对象设计的基石,封装是什么,封装有何用,这些常识性的问题在这里不做介绍。尽管JS是一种面向对象的语言,但是它不具备用以将成员声明为公用或私用的任何内置机制。与上篇讲述的接口一样,我们将自己想办法实现这种特性。这里主要利用了JS的闭包。什么是闭包,这里也不作讨论,这不是一个讨论JS语法的总结。


           2.JS创建自定义对象的基本方法

          通过JS创建自定义对象主要有两种方法,一种是通过字面量对象,这种方法等价于实例化一个Object对象,给实例化的对象添加各种属性和方法; 第二种是通过构造函数的形式实例化对象。以下代码展示了这两种创建对象的方法。

    [javascript] view plaincopy

        /*通过字面量创建对象,等价于var obj=new Object(); obj.name='xxx', obj.age=23, obj.getName=function(){return this.name;}*/
        var obj = {
            name: 'xxx',
            age: '23',
            getName:function(){
                  return this.name; },
           ..............
        };
          
        /*通过构造函数实例化一个对象*/
        function Person(name, age){
             this.name = name;
             this.age = age;
             this.getName=function(){
                      return this.name;
             };
        }
          
        var obj_person = new Person('xxx', 23);


    通过字面量创建对象常用于保存一些数据,或者实现一个简单的单例对象,我们可以看到,无法从这种创建对象的方法隐藏任何信息。

    通过构造函数实例化对象,很显然,非常符合面向对象的特点,且我们可以通过该方法实现封装的特性。


    3. 利用闭包和构造函数实现私有成员和特权方法

           假设你想定义一个Person类,这个Person包含有name, age这两个属性,同时对age字段还提供了对应的get和set操作,而name字段我们不希望有人去更改他,只提供get方法,同时为了规范, 每个私有成员的命名都应该以'_'开头,很自然的,你可以这样定义构造函数:

    [javascript] view plaincopy

        function Person(name, age){
             this._name = name;
             this._age = age;
             this.getAge = function(){
                  return this.age;
             };
             this.setAge = function(value){
                 if(value < 0){
                     throw new Error("Age of a Person cannot be a minus"); //人的年龄是不能为负数的,在这里做个简单的值检验
                 }
                 this.age = value;
             };
             this.getName = function(){
                 return this.name
             };


    事实上,这样只能从命名规范上来约束使用你的代码的程序员,如果用你的代码的程序员想更改这些目前所谓的私有成员,是非常容易的:

    只需 var obj = new Person(); obj._age = -10; 为了解决这类问题,我们可以按如下代码所示使用闭包实现私有成员:

    [javascript] view plaincopy

        function Person(name, age){
            if (age < 0) {
                throw new Error("Age of a Person cannot be a minus");
            }
              
            //私有成员,仅内部可见,只能通过特权方法访问
            var _name = name,
                _age = age;
              
            //get和set特权方法
            this.getName = function(){
                return _name;
            };
              
            this.getAge = function(){
                return _age;
            };
            this.setAge = function(value){
                if (value < 0) {
                    throw new Error("Age of a Person cannot be a minus");
                }
                _age = value;
            };
        }


          4. 用闭包实现私有成员的弊端
          从上面的闭包代码可以看到,内部访问私用成员的方法在每一个对象中都必须存在一份副本,即使他们实现的功能和代码是一样的,在普通的模式中,通过原型链可以只保存一份通用的方法,即可以这样定义类的get和set: Person.prototype.getName = function(){ return this.name; }; 因此通过闭包的形式实现的特权方法会造成更多的内存消耗,在开发团队中,一般通过命名规范的模式应该就可以保证私有成员的完整性。
       
        5. 静态方法和属性
        现在,假设我们的客户提出了一个新的需求,需要一个方法能统计人数,自然的这个人数就是Person实例化后的对象个数,同样我们很自然的想到可以通过一个静态变量来统计,再一次的,我们也不想别人可以任意的修改这个数值,因此我们同样通过闭包来实现私有的静态属性,并提供一个公共的静态方法让用户可以获得人数。同时,我们进一步细化原来的代码,把验证年龄合法性的代码封装成一个静态私有函数。 以下代码展示了上面所述的实现:

    [javascript] view plaincopy

        //这里使用了一个自运行函数实现闭包
        var Person = (function(){
            var personNumbers = 0; //静态私有成员,记录实例化个数
            function _checkAge(value){ //静态私有方法,检验年龄的合法性
                if (value < 0) {
                    throw new Error("Age of a Person cannot be a minus");
                }
            }
              
            var cstor = function(name, age){ //将返回的构造函数
                _checkAge(age);
                //私有成员,仅内部可见,只能通过特权方法访问
                var _name = name,
                    _age = age;
                      
                ++personNumbers;//增加实例化个数
                //get和set特权方法
                this.getName = function(){
                    return _name;
                };
              
                this.getAge = function(){
                     return _age;
                };
                this.setAge = function(value){
                    _checkAge(age);
                    _age = value;
                };
            };
              
            cstor.getPersonNumbers = function(){ //静态公有方法,返回实例化个数
                return personNumbers;
            };
              
            return cstor;
        })();


    上面的代码,我们使用了一个自运行函数实现了闭包,并实现了静态成员和静态方法, 对于静态私有成员来说,由于是相对于类(或者说构造函数)存在的,所以不会应为实例化对象的增加而增加,仅会保存一份。 所以静态私有成员无需担心内存的消耗。

  • 相关阅读:
    整理前端面试题1
    前端面试题2
    6.显示锁Lock 和 线程通信Condition
    5.创建执行线程的方式之三 :实现Callable 接口
    4.闭锁 CountDownLatch
    3.ConcurrentHashMap 锁分段机制 Copy-On-Write
    2.原子变量 CAS算法
    1.volatile关键字 内存可见性
    13.MyBatis注解式开发
    12.查询缓存
  • 原文地址:https://www.cnblogs.com/zjw520/p/3015459.html
Copyright © 2011-2022 走看看