Javascript 设计模式学习笔记(1) - 封装

    封装和信息隐藏

1. 信息隐藏原则

封装是面向对象编程特性之一, javascript 虽然是面向对象的编程语言, 却不像 Java / C++ 那样可以将成员属性声明为私有或是公有. 所以我们只能想办法模拟封装, javascript 也完全有能力完成这一任务.

封装( Encapsulation ), 可以定义为对对象内部数据表现形式和实现细节进行隐藏.  要想访问已经封装的数据只有使用已经定义的函数这一种方法. 也就是通过已定义的接口访问封装的数据.

2. 创建对象的基本模式

有三种:

1) fully exposed 是最简单的一种, 只能提供公有成员.

2) 用 下划线 来标识属性和方法的私有性, 只有提示程序员这是私有的, 但实际上并不是真正私有

3) 闭包创建真正私有的成员, 只能通过特定的方法访问.


(一) 门户大开型, 更夸张点 完全暴露型

这种类型有一个构造器, 属性和方法外部可以访问, 属性需要用 this 关键字来创建.

var Student = function(id, name) {
    if(!this.checkId(id)) throw new Error("Invalid Id!");
    this.id = id;// 假设 id 应该是私有成员变量
    this.name = name;
}
Student.prototype.checkId = function(id) {
    // 简单 check id
    if(typeof id != 'string' || id.length != 9) 
        return false;
}
var studentA = new Student();

上面的例子, 包含了一个对学生ID简单check的方法. 但是还是可能通过 studentA.id = "error" 这种方式更改实例的 id 属性, 而且这个 id 没有被 check . 这是我们不希望看到的情况. 为了改善这个问题, 我们会给这个每个属性都定义 get / set 方法. 然后在 set 方法中对参数进行应有的检验工作. 但是话又说回来, 就算有了 get / set 方法, id 属性还是公开的, 并没有改变, 还是可以通过 studentA.id = "error" 来设置.

总结一下这种方法的优缺点:

它易于使用, 初学者很快就能学会, 所有属性方法都公开, 派生子类和进行单元测试也很容易. 缺点是无法保护内部数据, 每个属性的 get / set 方法也会增加许多额外的代码.


(二) 用命名规范区别私有成员, 如 _

其实我认为, 这种方法也是第一种方法的加 get / set 是一个性质的.. 这种方法与上面的方法唯一不同的就是在私有成员的命名时以 _ 开始, 如: _id 和 _checkId().

如上面所说, 这仅仅是一种约定, 实质上还是阻止不了有的人用 studentA._id = "error" .


(三) 作用域 嵌套函数和闭包

var Student = function(id, name) {
  var sId, sName;
  function checkId() {/* do something */};
  this.getId = function() { return sId; }
}
var studentA = new Student('001',)


// 楼主已然崩溃, 本来本文已经写完, 写了很多, 但是CSDN的BLOG系统出了故障.....好了后只恢复到了这里, 心都凉了 - -

书接前文, 简单写点吧.. 私有成员用 var / function checkId() 声明, 而不是前面例子中的 this. 如果想 get / set  sId / sName 只有通过 getId() 这样的 特权方法来执行.

特权方法: 它们是公共方法, 但是却可以访问私有成员, 如上面的 getId()

更高级的创建对象方法

(一) 静态成员

var Student = (function() {
  var studentCount = 0; // static
  // 下面返回构造函数
  return function(sId, sName) {
    var sId, sName;
    function checkId() {/* do something */};
    this.getId = function() { return sId; }; 
  }
})();


这里创建了一个静态变量 studentCount , 静态成员是与类关联的而不是与类的实例关联. 当去判断某属性是否应为静态属性时, 也是依靠这点来的.

与前几个例子不同的是, 这里创建了一个加载后直接调用的函数, 返回内联的 Student 的构造函数.

(二) 常量

有了上面静态成员的模拟方法, 常量就容易模拟了, 拿上面的程序为例, 想要让 studentCount 为一个常量, 那么只需定义一个studentCount 的 get() 方法, 而不提供使用者 set()

方法, 那么就相当于模拟了一个常量.

总结:

介绍了几种创建对象的方法, 各有利弊, 用的时候权衡利弊, 作出适当的选择

Javascirpt 不提供内置的封装功能, 所以一切都要靠模拟, 使一切表现得复杂些, 比起 Java, C++, 但是这可能也是Javascript有趣儿的地方.

好了,,本来这篇写了挺多, 竟遇到blog system outage这种事儿, 后面没有第一次写的那么详细了, 请大家多指教 :)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值