单体模式
单体模式的思想在于保证一个特定的类仅有一个实例。这意味着第二次使用同一个类创建新对象的时候,应该得到与第一次所创建对象完全相同
js 中没有类,只有对象,创建新对象就已经是单体了
1 | var obj = {} |
js 中对象之间永远不会相等,除非是同一对像,所以每次使用对象字面量创建对象就是创建一个单体
使用 new 操作符
1 | var a = new Foo() |
上面代码中,a 对象仅在第一次调用构造函数时创建。第二次创建时将返回同一个 a 对象,使得 a === b,本质上是指相同一个对象的引用
js 实现单体需要 Foo 构造函数缓存该对象实例 this,以便第二次调用该构造函数时能够创建并返回同一个对象。实现这一目的有以下几种方法:
- 使用全局变量存储该实例。不过全局变量是有缺点的,不符合一般性原则,任何人都能覆盖全局变量
- 在构造函数的静态属性中缓存该实例。可以使用类似
Foo.instance的属性将实例缓存在该属性中,这种方案的缺点是 instance 属性是公开可访问的属性,代码外部中可能会修改该属性 - 将该实例包装在闭包中。这样可以保证实例的私有性,代价是带来了额外的闭包开销
静态属性实例
示例:
1 | function Foo() { |
闭包中的实例
示例:
1 | function Foo() { |
工厂模式
工厂模式的目的是为了创建对象。通常以类或类静态方法实现,有以下设计目标:
- 创建相似对象时执行重复操作。
- 编译不知道具体类型(类)的情况下,为工厂客户提供一种创建对象的接口。
示例:
1 | // 父构造函数 |
迭代器模式
迭代器通常是一个包含某种数据集合的对象。该数据可能存储在一个复杂数据结构内部,需要提供一个简单的方法访问数据结构中的每个元素。消费者只需要取出单个数据进行工作。
1 | var gen = (function () { |
装饰者模式
装饰者模式可以在运行时动态添加附加功能到对象中。
1 | // 添加一个原型方法和构造函数 |
使用列表实现
1 | function trimmer(options) { |
策略模式
此模式支持在运行时选择算法。
实现一个表单验证器:
1 | var validator = { |
外观模式
此模式为对象提供一个可供选择的接口。外观模式对重构和重新设计代码也很有帮助。通过外观模式可以优先考虑新对象的 API,在原有对象前面创建一个外观。这样仅须修改少量代码就可以取代原有对象。
当处理浏览器事件时有两个方法供调用:
1 | stopPropagation() |
当需要同时调用时可以创建一个外观方法同时调用这两个方法
1 | var event = { |
代理模式
代理模式中,一个对象充当另一个对象的接口。代理充当了某个对象的守护对象,并试图使本体对象做尽可能少的工作。
示例:
1 | <!DOCTYPE html> |
中介者模式
应用程序无论大小,都是由一些单个的对象组成。当这些对象需要一种方式来实现相互通信,这种通信一定程度上并不降低对代码的可维护性,也不会破坏程序的完整性。但是随着应用程序的增长,将添加越来越多的对象。这期间代码经历多次增删改。当对象膨胀的越来越大,不可避免地对象相互通信越来越多,这将会导致不良的耦合问题。这样导致后期最简单的修改将也变得不容易,几乎无法估计修改花费的时间。中介者模式缓解了这个问题,促进形成松耦合并且有助于提高可维护性。
示例:
1 | <!DOCTYPE html> |
观察者模式
此模式是一个对象订阅另外一个对象的特定活动并在状态改变后获得通知,订阅者也被称之为观察者,被观察的对象称为发布者或主题
示例 1:
1 | var publisher = { |
示例 2:
1 | <!DOCTYPE html> |