JS设计模式---3.封装

封装之利

  • 保证内部数据完整,易于重构
  • 弱化模块间耦合,提高对象可重用性

封装之弊

  • 单元测试困难,错误调试困难
  • 过度封装会损失类的灵活性
  • 对新手不友好

创建对象的基本模式

需求:创建一个存储一本书的类,并为其实现一个以HTML形式显示数据的方法。你只负责创建这个类,别人会创建和使用其实例。

// 使用方式
var theHobbit = new Book('0-395-07122-4','The Hobbit','J.R.R. Tolkien');
theHobbit.display() // 以HTML形式显示数据
门户大开型对象
  var Publication = new interface('Publication', ['getIsbn', 'setIsbn', 'getTitle', 'setTitle', 'getAuthor',
    'setAuthor', 'display'
  ])
  var Book = function (isbn, title, author) {
    this.setIsbn(isbn);
    this.setTitle(title);
    this.setAuthor(author);
  }
  Book.prototype = {
    checkIsbn = function (isbn) {
      // ...
    },
    getIsbn: function () {
      return this.isbn;
    },
    setIsbn: function (isbn) {
      if (!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN');
      this.isbn = isbn;
    },
    getTitle: function () {
      return this.title;
    },
    setTitle: function (title) {
      this.title = title || 'No title specified';
    },
    getAuthor: function () {
      return this.author;
    },
    setAuthor: function (author) {
      this.author = author || 'No author specified';
    },
    display: function () {
      //  ...
    }
  }

上述代码定义了一个接口,那么其他程序员就应该只能使用接口中定义的属性和方法。
这是门户大开型对象创建方式所能得到的最好结果。一个明确定义的接口,一些数据的赋值器和取值器,及一些检验方法。
缺点就是虽然我们定义了赋值器方法,但是这些属性仍然是公开的、可以直接设置的。

命名规范区分私有成员
 var Book = function (isbn, title, author) {
    this.setIsbn(isbn);
    this.setTitle(title);
    this.setAuthor(author);
  }
  Book.prototype = {
    _checkIsbn = function (isbn) {
      // ...
    },
    getIsbn: function () {
      return this._isbn;
    },
    setIsbn: function (isbn) {
      if (!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN');
      this._isbn = isbn;
    },
    getTitle: function () {
      return this._title;
    },
    setTitle: function (title) {
      this._title = title || 'No title specified';
    },
    getAuthor: function () {
      return this._author;
    },
    setAuthor: function (author) {
      this._author = author || 'No author specified';
    },
    display: function () {
      //  ...
    }
  }

这是一种程序员约定俗成的方法,加下划线表示私有变量。但是JS中跟本没有私有变量的定义,只能说是总所周知的命名规范。缺点也很明显,既然是约定,那么只有在遵守时才有效果。

闭包实现私用成员
 var Book = function (newIsbn, newTitle, newAuthor) {
    //私有属性
    var isbn, title, author;
    // 私有方法
    function checkIsbn(isbn) {
      // ...
    };
    // 特权方法
    this.getIsbn = function () {
      return isbn;
    };
    this.setIsbn = function (newIsbn) {
      if (!checkIsbn(newIsbn)) throw new Error('Book:Invalid ISBN');
      isbn = newIsbn;
    };
    this.getTitle = function () {
      return title;
    };
    this.setTitle = function (newTitle) {
      title = newTitle || 'NO title specified';
    };
    this.getAuthor = function () {
      return author;
    };
    this.setAuthor = function (newAuthor) {
      author = newAuthor || 'NO author specified';
    };
    //  构造函数 赋值
    this.setIsbn(newIsbn);
    this.setTitle(newTitle);
    this.setAuthor(newAuthor);
  };
 // 公共方法
  Book.prototype = {
    display() {
      // ...
    }
  }

这种方式创建的对象具有真正的私有属性,解决了可以直接取值赋值的问题。缺点是会耗费更多的内存,而且不利于派生子类。在JS中,用闭包实现私用成员导致的派生问题被称为”继承破坏封装“。

MORE

静态成员

作用域和闭包可用于创建静态成员。大多数方法和属性所关联的是类的实例,而静态成员所关联的是类本身。

  • 一个栗子
  var Book = (function () {
    // 私有静态属性
    var numOfBookes = 0;
    // 私有静态方法
    function checkIsbn(isbn) {
      // ...
    };
    // 返回构造器
    return function (newIsbn, newTitle, newAuthor) {
      // 私有属性
      var isbn, title, author;
      // 特权方法
      this.getIsbn = function () {
        return isbn;
      };
      this.setIsbn = function (newIsbn) {
        if (!checkIsbn(newIsbn)) throw new Error('Book:Invalid ISBN');
        isbn = newIsbn;
      };
      this.getTitle = function () {
        return title;
      };
      this.setTitle = function (newTitle) {
        title = newTitle || 'NO title specified';
      };
      this.getAuthor = function () {
        return author;
      };
      this.setAuthor = function (newAuthor) {
        author = newAuthor || 'NO author specified';
      };

      numOfBookes++;
      if (numOfBookes > 50) {
        throw new Error('Book:Only 50 instance of book can be created.')
      }

      // 赋值
      this.setIsbn(newIsbn);
      this.setTitle(newTitle);
      this.setAuthor(newAuthor);
    }
  })();
  // 公共静态方法
  Book.converToTitleCase = function (inputString) {
    // ...
  };
  // 公共方法 非特权
  Book.prototype = {
    display:function() {
      // ...
    }
  }

闭包,返回一个构造器,私用成员和特权成员仍然在构造器中。但是闭包中可以访问静态成员。优点在于所有的静态成员只会存在一份,这样大大减小了内存的消耗。
q:如何判断是否设计成静态成员?
a:一般情况下,我们只需要看一个属性或者方法是否需要访问实例数据。如果不需要,那么设计成静态成员会更有效率。

常量

常量的取值

  var Class = (function () {
    var constans = {
      UPPER_BOUND: 100,
      LOWER_BOUND: -100
    };
    var ctor = function () {
      // ...
    }
    // 特权静态方法
    ctor.getConstans = function (name) {
      return constans[name];
    }
    return ctor
  })()
  // 取值
  Class.getConstans('UPPER_BOUND')
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,101评论 1 32
  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,743评论 0 14
  • 今天,不知道多少人单方面失恋了,是的,宋仲基和宋慧乔公布婚讯了。看到这条消息,我的CP粉特质也冒出来了,看...
    蓝梓恩阅读 196评论 0 0
  • 每天早起来,都还能看到虚月挂与空中,呼吸着清晨最清新的空气,仿若自己以漂浮与大地之间。 这两天阳光如此娇嫩,以...
    历练成圣阅读 150评论 0 0