Skip to content

JS 设计模式 #69

@coconilu

Description

@coconilu

概述

设计模式可以提高编程技巧,但是太过于追求设计模式,会适得其反。

创建型设计模式

对于创建型设计模式,闭包绝对是利器,特别是对于下面的设计模式:

  1. 单例模式
  2. 模块模式

jQuery库也是通过闭包来实现的,整个库的出口是jQuery对象,作者把它挂载到全局对象的jQuery$。闭包可以很好的保护“私有变量”。

JS没有严格的类概念,也没有严格的继承概念。但是对象原型可以帮我们存放对象的共有属性、方法,所以通过Object.create()和下面的设计模式:

  1. 原型模式

我们就可以创建很多共有原型的对象,Object.create()的第二个参数还可以提供对象差异化属性。还有function的prototype也同样可以办到。

相对于原型模式,还有另一种模式需要提一下:

  1. 混入(Mixin)模式

它和原型模式很像,不同的地方在于,混入模式会入侵原构造函数的原型,因为混入模式中的混入对象是使用类似Object.assign()的方式加入到构造函数的原型,它会覆盖原型中重名部分。好处是混入模式没有影响原型链的关系。

很多时候,用户并不喜欢使用new来构造新对象,此时我们需要提供一个统一的接口给用户,让用户仅通过输入配置就可以拿到自己想要的对象,这就是下面的设计模式:

  1. 工厂模式

工厂模式并没有强制特定的实现方式,不过有一种很推荐的方式就是,把工厂模式可以提供的对象的构造函数放在工厂对象的原型链上,然后工厂对象对外提供一个统一的接口,该接口接收用户的配置,并根据配置去装配新对象返回给用户。

结构型设计模式

1. 外观模式

很多第三方库都会使用外观模式,隐藏内部系统的实现,并提供用户易懂的接口,像jQuery、Lodash等等。

2. 装饰者模式

装饰者模式用于为现有的功能添加一些附加的功能,而不改变原有的功能。它的主要想法是,装饰的部分对于原有的基本功能来说并不是必要的(否则它就应该被合并到超类 / 原型上了)。

所以使用装饰者模式的大概有以下几种常见场景:

  1. 装饰父类的属性或者方法
  2. 提供一系列的链式调用的修饰方法去改变一个对象的内部属性,每个修饰方法内部都会维护自己的状态

3. 享元模式

享元模式出现的场景大多是需要大量对象的,然后区分开每个对象的内部状态和外部状态,外部状态可以由某个对象统一管理,可以节省很多系统资源。

有两个常见的场景:

  1. 用于数据层,处理内存中保存的大量相似对象的共享数据
  2. 用于DOM层,当做中央事件管理器,避免将事件处理器附加到父容器中的每个子元素上

行为设计模式

1. 观察者模式和Publish / Subscribe模式

数据获取的方式有两种:

  1. 拉取
  2. 推送

观察者模式和Publish / Subscribe模式就属于推送消息,不同的是:

观察者模式中的目标和观察者是直接联系的,而Publish / Subscribe模式在Publisher和Subscriber之间有主题 / 事件通道。

观察者模式被使用在vuejs库里的响应式系统里,而vuejs库里的事件订阅系统就是使用Publish / Subscribe模式。

2. 中介者模式

如果一个系统的各个组件之间看起来有太多的直接关系,那么就很需要一个中心控制点,保证组件的交互是通过这个中心点来处理的,而不是通过显示地引用彼此,这就是中介者模式。

大多数情况下,中介者模式会结合Publish / Subscribe模式一起使用,所有组件都可以通过发布事件来修改中心的状态,所有组件都可以在中心订阅某个主题 / 事件。VueJs的Vuex就是这样实现的。

3. 命令模式

命令模式的主要用途是把调用对象(用户界面、API和代理等)与实现操作的对象隔离开。凡是两个对象间互动方式需要有更高的模块化程度时都可以用到这种模式。

这个模式一般会有三个功能对象:

  1. 命令
  2. 命令接收者
  3. 命令执行者

命令是由调用者发起,由命令接收者统一接收,然后分发给特定的命令执行者。这样做的好处是,如果未来需要调整一个命令的功能,不需要大量重构代码,只需要在命令接收者处处理就好。

参考

《JavaScript 设计模式》

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions