概念
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢 的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
设计原则(5个)
S – Single Responsibility Principle 单一职责原则
- 一个程序只做好一件事
- 如果功能过于复杂就拆分开,每个部分保持独立
O – OpenClosed Principle 开放/封闭原则
- 对扩展开放,对修改封闭
- 增加需求时,扩展新代码,而非修改已有代码
L – Liskov Substitution Principle 里氏替换原则
- 子类能覆盖父类
- 父类能出现的地方子类就能出现
I – Interface Segregation Principle 接口隔离原则
- 保持接口的单一独立
- 类似单一职责原则,这里更关注接口
D – Dependency Inversion Principle 依赖倒转原则
- 面向接口编程,依赖于抽象而不依赖于具
- 使用方只关注接口而不关注具体类的实现
设计模式的类型
如果从作用上来划分,JavaScript设计模式大概分为五种设计类型:
创建型设计模式 | 结构型设计模式 | 行为型设计模式 | 技巧型设计模式 | 架构型设计模式 |
---|---|---|---|---|
简单工厂模式 | 外观模式 | 模板方法模式 | 链模式 | 同步模块 |
工厂方法模式 | 适配器模式 | 观察者模式 | 委托模式 | 异步模块模式 |
抽象工厂模式 | 代理模式 | 状态模式 | 数据访问对象模式 | Widget模式 |
建造者模式 | 装饰者模式 | 策略模式 | 节流模式 | MVC模式 |
原型模式 | 桥接模式 | 职责链模式 | 简单模板模式 | MVP模式 |
单例模式 | 组合模式 | 命令模式 | 惰性模式 | MVVM模式 |
享元模式 | 访问者模式 | 参与者模式 | ||
中介者模式 | 等待者模式 | |||
备忘录模式 | ||||
迭代器模式 | ||||
解释器模式 |
第 33 章 异国战场-参与者模式
- 参与者模式:在特定的作用域中执行给定的函数,并将参数原封不动地传递。
事件绑定方法
1 | let A = { |
1 | /*上面存在的问题, addEventListener 没有办法在回调函数中传递参数, 做如下的修改*/ |
通过 call 和 apply 方法使我们在特定作用域中执行某个函数并传入参数。
实现 bind 方法
1 | /* |
bindFn返回了结果,因为 bindFn 在执行时 demoObj 参与了进来并提供了作用域。
1 | /* |
不使用实现的 bind 方法,我们也可以用原生的 bind
1 | let bindFN = demoFn.bind() |
函数柯里化
1 | /* |
函数柯里化(function currying)又称部分求值。一个函数首先会接受一些参数,接受了这些参数后,
该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包里被保存起来。待到函数真正需要求值的时候,之前传入的参数都会被一次性用于求值。
把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。
1 | let curry = function (fn) { |
对 add 方法的多态扩展不需要再声明函数了。
通过柯里化重写 bind
1 | /* |
以之前的 button 为例,我们现在能在回调函数中获取传递的自定义的数据了。
1 | let bindFn = demoFn.bind(button, demoData1); // [Object, MouseEvent] <button>按钮</button> 事件对象放后面的 |
1 | /* |
总结
对于函数绑定,将函数以函数指针(函数名的方式传递),使函数在被绑定对象上的作用域中执行,可以顺利访问到对象内部的数据。缺点会消耗更多的内存执行速度会稍慢。比较常用于事件,setTimeout等异步逻辑的回调函数。
对于函数柯里化则是将接受多个参数的函数转化成接受一部分参数的新函数,余下的参数保存下来。当调用式传入的参数和保存的参数一起执行。因为要保存参数到闭包内,所以同样也会多消耗些资源。
第 34 章 入场模式-等待者模式
等待者模式: 通过对多个异步进程进行监听,来触发未来的动作。(构建简易Promise对象,实现状态机)
场景: 不能确定先后的异步逻辑,但需要等待所有异步逻辑的完成。所有成功后执行成功回调,有一个失败就执行失败的回调函数。
不需要实时监听所有异步逻辑是否完成,只需要监听注册的异步逻辑的状态发生改变时,对所有的异步逻辑的状态进行一次确认迭代。
接口拆分
一个等待者对象内部定义了3个数组,分别存储监听对象,成功回调和失败回调;1个监控对象的类,有2个属性(成功状态和失败状态),2个方法(成功和失败方法);私有方法_exec来处理成功或失败的回调;3个共有方法接口:when(监听异步逻辑)、done(添加成功回调)、fail(添加失败回调)
1 | // 等待者对象 |
监控对象类原型方法
1 | Primise.prototype = { |
回调执行方法
1 | function _exec(arr){ |
监控异步方法 参数:监控对象
1 | that.when = function() { |
解决成功回调函数添加方法
1 | that.done = function() { |
解决失败回调函数添加方法
1 | that.fail = function() { |
测试
1 | // 创建一个等待者对象 |
应用场景
1 | // 封装get请求 |
总结
等待者模式适合用于处理比较耗时的操作比如定时器操作、异步请求等。等待者模式提供了抽象非阻塞的解决方案。通过创建 Promise 对象,对应状态变化返回响应,同时监听这些响应信息,并为之提供相应的回调,根据状态执行相应的回调方法。