工厂模式
- 将new操作单独封装
- 遇到new时,就要考虑是否该使用工厂模式
UML类图
实现
class Product {
constructor(name) {
this.name = name
}
init() {
console.log('init')
}
fun1() {}
fun2() {}
}
class Creator {
creat(name) {
return new Product(name)
}
}
// 测试
let creator = new Create()
let p = creator.create('p1')
场景
- jQuery-$(‘div’)
- React.createElement
- Vue异步组件
单例模式
- 系统中被唯一使用
- 一个类只有一个实例
UML类图
实现
class SingleObject {
login() {
console.log('login')
}
}
SingleObject.getInstance = (function() {
let instance
return function() {
if(!instance) {
instance = new SingleObject()
}
return instance
}
})()
// 测试:只能使用静态函数getInstance,不能new SingleObject()
let obj1 = SingleObject.getInstance()
let obj2 = SingleObject.getInstance()
obj1 === obj2 // ture
场景
- jQuery只有一个$
- 登录框
- 购物车
- vuex和redux中store
适配器模式
- 旧接口格式和使用者不兼容
- 中间加一个适配转换接口
UML类图
实现
class Adaptee {
specificRequest() {
return '外国插头'
}
}
class Target {
constructor() {
this.adaptee = new Adaptee()
}
request() {
let info = this.adaptee.specificRequest()
return '转换后中国插头'
}
}
// 测试
let target = new Target()
target.request()
场景
- 封装旧接口
- vue computed
装饰器模式
- 为对象添加新功能
- 不改变其原有的结构和功能
UML类图
实现
class Circle {
draw() {
console.log('画圆形')
}
}
class Decorator {
constructor(circle) {
this.circle = circle
}
draw() {
this.circle.draw()
this.setRedBorder(circle)
}
setRedBorder(circle) {
console.log('设置红色边框')
}
}
// 测试
let circle = new Circle()
circle.draw()
let dec = new Decorator(circle)
dec.draw()
场景
- ES7装饰器
// 装饰类
function testDec(isDec) {
return function(target) {
target.isDec = isDec
}
}
@testDec(false)
class Demo {
}
console.log(Demo.isDec)
// 装饰类
function mixins(...list) {
return function(target) {
Object.assign(target.prototype,...list)
}
}
const Foo = {
foo() {
console.log('foo')
}
}
@mixin(Foo)
class MyClass {
}
let obj = new MyClass()
obj.foo()
// 装饰方法
function readonly(target, name, descriptor) {
// descriptor属性描述对象(Object.defineProperty中会用到),原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// }
descriptor.writable = false
return descriptor
}
class Person {
constructor() {
this.first = 'A'
this.last = 'B'
}
@readonly
name(){
return this.first + this.last
}
}
let p = new Person()
console.log(p.name())
p.name = function() {
}
// 装饰方法
function log(target, name, descriptor) {
let oldValue = descriptor.value
descriptor.value = function() {
console.log(name,arguments)
return oldValue.apply(this,arguments)
}
return descriptor
}
class Math {
@log
add(a, b) {
return a + b
}
}
let math = new Math()
const result = math.add(2, 4)
- core-decorators
代理模式
- 使用者无权访问目标对象
- 中间加代理,通过代理做授权和控制
UML类图
实现
class ReadImg {
constructor(fileName) {
this.fileName = fileName
this.loadFromDisk() // 初始化
}
display() {
console.log(this.fileName)
}
loadFromDisk() {
console.log(this.fileName)
}
}
class ProxyImg {
constructor(fileName) {
this.realImg = new ReadImg(fileName)
}
display() {
this.realImg.display()
}
}
// 测试
let proxyImg = new ProxyImg('a.png')
proxyImg.display()
场景
- 网页事件代理
- jQuery-$.proxy
- ES6 Proxy
外观模式
- 为子系统中的一组接口提供了一个高层接口
- 使用者使用这个高层接口
UML类图
实现
function bindEvent(elem, type, selector, fn) {
if(fn == null) {
fn = selector
selector = null
}
// ...
}
// 调用
bindEvent(elem, 'click', '#div1', fn)
bindEvent(elem, 'click', fn)
场景
- 业务子系统
观察者模式
- 发布&订阅
- 一对多
UML类图
实现
// 主题,保存状态,状态变化之后触发所有观察者对象
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
attach(observer) {
this.observers.push(observer)
}
}
// 观察者
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(this.name, this.subject.getState())
}
}
// 测试
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
s.setState(1)
场景
-
网页事件绑定
-
Promise
-
jQuery callbacks
-
nodejs自定义事件
-
nodejs中:处理http请求;多进程通讯
-
Vue和React组件生命周期触发
-
Vue watch
迭代器模式
- 顺序访问一个集合
- 使用者无需知道集合的内部结构(封装)
UML类图
实现
class Iterator {
constructor(container) {
this.list = container.list
this.index = 0
}
next() {
if(this.hasNext()){
return this.list[this.index++]
}
return null
}
hasNext() {
if(this.index >= this.list.length){
return false
}
return true
}
}
class Container {
constructor(list) {
this.list = list
}
// 生成遍历器
getIterator() {
return new Iterator(this)
}
}
// 测试
let arr = [1, 2, 3, 4, 5, 6]
let container = new Contaienr(arr)
let iterator = container.getIterator()
while(iterator.hasNext()) {
console.log(iterator.next())
}
场景
- jQuery each
- ES6 Iterator
- ES6语法中,有序集合的数据类型已经有很多
- Array、Map、Set、String、TypedArray、arguments、NodeList
- 需要有一个统一的遍历接口来遍历所有数据类型
- 以上数据类型,都有[Symbol.iterator]属性
- 属性值是函数,执行函数返回一个迭代器
- 这个迭代器就有next方法可顺序迭代子元素
- 可运行Array.prototype[Symbol.iterator]来测试
function each(data) {
// 生成遍历器
let iterator = data[Symbol.iterator]()
let item = {done: false}
while(!item.done) {
item = iterator.next()
if(!item.done){
console.log(item.value)
}
}
}
function(each) {
// 带有遍历器特性的对象,data[Symbol.iterator]有值
for(let item of data) {
console.log(item)
}
}
状态模式
- 一个状态有状态变化
- 每次状态变化都会触发一个逻辑
- 不能总是用if…else来控制
UML类图
实现
// 状态(红灯、绿灯、黄灯)
class State {
constructor(color) {
this.color = color
}
handle(context) {
console.log(this.color)
context.setState(this)
}
}
class Context {
constructor() {
this.state = null
}
getState() {
return this.state
}
setState(state) {
this.state = state
}
}
// 测试
let context = new Context()
let green = new State('green')
let yellow = new State('yellow')
let red = new State('red')
green.handle(context)
context.getState()
场景
-
有限状态机
开源lib:javascript-state-machine
-
Promise
其他设计模式
- 策略模式、模版方法模式、职责链模式
- 命令模式、备忘录模式、中介者模式
- 访问者模式、解释器模式
原型模式
- clone自己,生成一个新对象
// 一个原型对象
const prototype = {
getName: function() {
return this.first + '' + this.last
},
say: function() {
console.log('hello')
}
}
// 基于原型创建x
let x = Object.create(prototype)
x.first = 'A'
x.last = 'B'
console.log(x.getName())
x.say()
// 基于原型创建x
let y = Object.create(prototype)
y.first = 'C'
y.last = 'C'
console.log(y.getName())
y.say()
桥接模式
- 用于把抽象化和实现化解耦
- 使得二者可以独立变化
class Color {
constructor(name) {
this.name = name
}
}
class Shape {
constructor(name, color) {
this.name = name
this.color = color
}
draw() {
console.log(this.color.name, this.name)
}
}
let red = new Color('red')
let yellow = new Color('yellow')
let circle = new Shape('circle', red)
circle.draw()
let triangle = new Shape('triangle', yellow)
triangle.draw()
组合模式
- 生成树形结构,表示“整体-部分”关系
- 让整体和部分都具有一致的操作方式
享元模式
- 共享内存(主要考虑内存,而非效率)
- 相同的数据,共享使用
策略模式
- 不同策略分开处理
- 避免出现大量if…else或者switch…case
class User {
constructor(type) {
this.type = type
}
buy() {
if(this.type === 'ordinary'){
console.log('普通用户')
}else if(this.type === 'member'){
console.log('会用用户')
}else if(this.type === 'vip'){
console.log('vip用户')
}
}
}
let u1 = new User('ordinary')
u1.buy()
let u2 = new User('member')
u2.buy()
let u3 = new User('vip')
u3.buy()
class OrdinaryUser {
buy() {
console.log('普通用户')
}
}
class MemberUser {
buy() {
console.log('会用用户')
}
}
class VipUser {
buy() {
console.log('vip用户')
}
}
let u1 = new OrdinaryUser()
let u2 = new MemberUser()
let u3 = new VipUser()
模板方法模式
- 内部特殊顺序特殊逻辑方法封装、合并
- 输出统一对外方法
class Action {
handle() {
this.handle1()
this.handle2()
this.handle3()
}
handle1() {}
handle2() {}
handle3() {}
}
职责链模式
- 一步操作可能分多个职责角色来完成
- 把角色分开,然后用链串起来
- 将发起者和各个处理者进行隔离
// 请假审批
class Action {
constructor(name) {
this.name = name
this.nextAction = null
}
setNextAction(action) {
this.nextAction = action
}
handle() {
console.log(this.name)
if(this.nextAction != null){
this.nextAciton.handle()
}
}
}
let a1 = new Action('组长')
let a2 = new Action('经理')
let a3 = new Action('总监')
a1.setNextAction('a2')
a2.setNextAction('a3')
a1.handle()
命令模式
- 执行命令时,发布者和执行者分开
- 中间加入命令对象,作为中转站
// 接受者
class Receiver {
exec() {
console.log('执行')
}
}
// 命令者
class Command {
constructor(receiver) {
this.receiver = receiver
}
cmd() {
console.log('执行命令')
this.receiver.exec()
}
}
// 触发者
class Invoker {
constructor(command) {
this.command = command
}
invoke() {
console.log('开始')
this.command.cmd()
}
}
// 士兵
let soldier = new Receiver()
// 小号手
let trumpeter = new Command(soldier)
// 将军
let general = new Invoker(trumpeter)
general.invoke()
备忘录模式
- 随时记录一个对象的状态变化
- 随时可以恢复之前的某个状态(如撤销功能)
// 备忘类
class Memento {
constructor(content) {
this.content = content
}
getContent() {
return this.content
}
}
// 备忘列表
class CareTaker {
constructor() {
this.list = []
}
add(memento) {
this.list.push(memento)
}
get(index) {
return this.list[index]
}
}
// 编辑器
class Editor {
constructor() {
this.content = null
}
setContent(content) {
this.content = content
}
getContent() {
return this.content
}
saveContentToMemento() {
return new Memento(this.content)
}
getContentFromMenento() {
this.content = memento.getContent()
}
}
let editor = new Editor()
let careTaker = new CareTaker()
editor.setContent('111')
editor.setContent('222')
careTaker.add(editor.saveContentToMemento()) // 将当前内容备份
editor.setContent('333')
careTaker.add(editor.saveContentToMemento()) // 将当前内容备份
editor.setContent('444')
console.log(editor.getContent())
editor.getContentFromMenento(careTaker.get(1)) // 撤销
console.log(editor.getContent())
editor.getContentFromMenento(careTaker.get(0)) // 撤销
console.log(editor.getContent())
中介者模式
class A {
constructor() {
this.number = 0
}
setNumber(num, m) {
this.number = num
if(m){
m.setB()
}
}
}
class B {
constructor() {
this.number = 0
}
setNumber(num, m) {
this.number = num
if(m){
m.setA()
}
}
}
// 中介者
class Mediator {
constructor(a, b) {
this.a = a
this.b = b
}
setB() {
let number = this.a.number
this.b.setNumber(number * 100)
}
setA() {
let number = this.b.number
this.a.setNumber(number / 100)
}
}
let a = new A()
let b = new B()
let m = new Mediator(a, b)
a.setNumber(100, m)
console.log(a.number, b.number)
b.setNumber(100, m)
console.log(a.number, b.number)
访问者模式
- 将数据操作和数据结构进行分离
解释器模式
- 描述语言语法如何定义,如何解释和编译