做者:gauseenjavascript
Singleton Pattern
)描述:html
只对外暴露一个对象前端
// 只建立一个实例 const mySingleton = (function () { let instance = null // 初始化方法 let init = () => { console.log('init logic') return { someThing () { alert('hello world') }, } } return { getInstance () { // 不存在 instance 建立新的,已存在则直接返回(只建立一次) if (!instance) { instance = init() } return instance }, } })()
// 每次都建立一个新的实例 const myBadSingleton = (function () { let instance = null // 初始化方法 let init = () => { console.log('init logic') return { someThing () { alert('hello world') }, } } return { getInstance () { // 每次都建立一个新的实例(建立屡次) instance = init() return instance }, } })()
Observer Pattern
)真实场景:java
以公众号为例,有些人订阅(关注)了某公众号,当公众号发布新的消息时,订阅者就会收到该消息的推送git
描述:github
定义对象之间的依赖关系,每当对象更改状态时,都会通知全部依赖项浏览器
// 观察者 class Observer { constructor (name) { this.name = name } // 每一个观察者都有一个 smile 事件 update () { console.log(`${this.name} is updated`) } } // 主体 class Subject { constructor () { // 观察者列表 this.observers = [] } // 添加观察者到主体的观察者列表 subscribe (observer) { this.observers.push(observer) } // 通知全部观察者 notify () { this.observers.forEach(observerItem => { observerItem.update() }) } } // 建立主体实例 const subject = new Subject() // 有 2 个观察者 observer0一、observer02 const observer01 = new Observer('observer_01') const observer02 = new Observer('observer_02') // 观察者订阅主体 subject.subscribe(observer01) subject.subscribe(observer02) // 通知全部观察者 subject.notify()
Publish/Subscribe Pattern
)真实场景:post
报社将报纸发送给邮局,邮局按照订阅关系将报纸发送给对应的人this
描述:spa
消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不一样的类别,无需了解哪些订阅者。一样的,订阅者能够订阅一个或多个类别,只接收感兴趣的消息,无需了解哪些发布者
// 订阅者 class Subscriber { constructor (name) { this.name = name } // 每一个观察者都有一个 smile 事件 update () { console.log(`${this.name} is updated`) } } // 调度中心 class EventHub { constructor () { // 订阅主题 this.topics = {} } // 订阅 subscribe (topicType, subscriber) { if (!this.topics[topicType]) { this.topics[topicType] = [] } this.topics[topicType].push(subscriber) } // 给对应主题下的订阅者发布内容 publish (topicType) { let topicList = this.topics[topicType] if (!topicList) return topicList.forEach(subscriberItem => { subscriberItem.update() }) } } // 建立一个“调度中心” let eventHub = new EventHub() // 建立 3 个订阅者 subscriber0一、subscriber0二、subscriber03 let subscriber01 = new Subscriber('subscriber_01') let subscriber02 = new Subscriber('subscriber_02') let subscriber03 = new Subscriber('subscriber_03') // 订阅者注册“调度中心” eventHub.subscribe('typeA', subscriber01) eventHub.subscribe('typeA', subscriber02) eventHub.subscribe('typeB', subscriber03) // 发布者对 typeA 主题发布内容 eventHub.publish('typeA') // subscriber_01 is updated // subscriber_02 is updated // 发布者对 typeB 主题发布内容 eventHub.publish('typeA') // subscriber_03 is updated
如上图
Subject
)和观察者(Observer
)是强耦合,有直接的联系,相互知道对方的存在。Subject
)和观察者(Observer
)是松耦合,没有直接的联系,是经过“事件通道”(调度中心)创建联系,互相不知道对方存在。奇葩解释:观察者模式,没中间商赚差价;发布-订阅模式,有中间商赚差价
Factory Pattern
)class CarA { constructor (model, color) { console.log('CarA') } } class CarB { constructor (model, color) { console.log('CarB') } } class CarFactory { carA () { return CarA } carB () { return CarB } create (type) { let CarClass = this[type]() return new CarClass() } } let carFactory = new CarFactory() // 经过 carFactory 建立不一样的 car let carA = carFactory.create('carA') let carB = carFactory.create('carB')
Adapter Pattern
)真实场景:
如今好多智能手机都去掉了 3.5mm
的耳机孔,取而代之的是 Type-C
接口耳机。可是你还想在新手机中使用 3.5mm
的老式耳机怎么办?
没错,那就须要用适配器,Type-C
转 3.5mm
的适配器。以下图 :
描述:
能够将其余不兼容的对象包装在适配器中,使它与另外一个类兼容
// Type-C 耳机 class TypecHeadset { typeC () { console.log('Type-C 耳机已插入') } } // 3.5 毫米耳机 class Dot35mmHeadset { dot35mm () { console.log('3.5mm 耳机已插入') } } // 适配器(3.5 毫米 --> Type-C) class Dot35mmToTypecAdapter { constructor (dot35mmHeadset) { this.dot35mmHeadset = dot35mmHeadset } typeC () { this.dot35mmHeadset.dot35mm() } } // 手机类(该手机只支持 Type-C 耳机) class Phone { // 插入耳机孔 insertTypeC (headset) { headset.typeC() } } let phone = new Phone() // Type-C 耳机 let typecHeadset = new TypecHeadset() // 3.5 毫米耳机 let dot35mmHeadset = new Dot35mmHeadset() // 耳机适配器(3.5 毫米 --> Type-C) let dot35mmToTypecAdapter = new Dot35mmToTypecAdapter(dot35mmHeadset) phone.insertTypeC(typecHeadset) // Type-C 耳机已插入 phone.insertTypeC(dot35mmToTypecAdapter) // 3.5mm 耳机已插入
Decorator Pattern
)真实场景:
先建一个基础版本的手机,通过再加工对手机进行装饰润色,
描述:
装饰者模式,容许你经过将对象包装在装饰器类的对象中,来动态更改对象在运行时的表现行为
// 基础 car 类 class SimpleCar { getCost () { return 10 } getDescription () { return 'Simple car' } } // 奥迪 class AudiCar { constructor (car) { this.car = car } getCost () { return this.car.getCost() + 6 } getDescription () { return this.car.getDescription() + ', Audi' } } // 宝马 class BMWCar { constructor (car) { this.car = car } getCost () { return this.car.getCost() + 8 } getDescription () { return this.car.getDescription() + ', BMW' } } // 基础车信息 let simpleCar = new SimpleCar() simpleCar.getCost() // 10 simpleCar.getDescription() // Simple car // 奥迪车信息 let audiCar = new AudiCar(simpleCar) audiCar.getCost() // 16 audiCar.getDescription() // Simple car, Audi // 宝马车信息 let bmwCar = new BMWCar(simpleCar) bmwCar.getCost() // 18 bmwCar.getDescription() // Simple car, BMW
Facade Pattern
)真实场景:
如何让手机开机?很简单,“长按电源键”便可开机。实际上手机内部处理了不少逻辑才能实现它。这就是所谓的外观模式,将复杂转为简洁。
例如,开发时经常使用于浏览器兼容性处理的代码。
描述:
为复杂的子系统提供了简化统一的界面
// DOM 绑定事件的兼容性处理 function addEventFacade (el, eve, fn) { if (el.addEventListener) { el.addEventListener(eve, fn, false) } else if (el.attachEvent) { el.attachEvent('on' + eve, fn) } else { el['on' + eve] = fn } }
Proxy Pattern
)真实场景:
你能够直接去专卖店买手机(某海外品牌),也能够经过代购帮你买手机(这样价格会便宜些)。让代购买手机这种方式,就是所谓的代理模式。
js
原生也支持代理模式 Proxy
描述:
用一个对象来表示另外一个对象的功能
class Phone { constructor () { this.phoneName = 'Mate 90' // 手机名 this.screen = '6.21' // 尺寸 this.color = 'black' // 颜色 this.chip = 'kirin' // 芯片 } } class ProxyPerson { constructor(target) { this.target = target } buyPhone (phoneModel) { this.target.buyPhone(phoneModel) } } class Person { buyPhone (phoneModel) { console.log('哈哈,买到了: ', phoneModel.phoneName) } } let proxyPerson = new ProxyPerson(new Person()) proxyPerson.buyPhone(new Phone()) // 哈哈,买到了: Meta 90
Strategy Pattern
)真实场景:
商店打折促销,某商品买 1
件原价,2
件 8
折,3
件 7
折
描述:
在代码运行时,根据不一样状况切换不一样的策略(方法)
// 策略组 const strategies = { num1 (price) { return price * 1 }, num2 (price) { return price * 0.8 }, num3 (price) { return price * 0.7 }, } // 获取折后总价 function getDiscountPrice (n, price) { let _key = `num${n}` let discountedForItem = strategies[_key](price) return discountedForItem * n } getDiscountPrice(1, 10) // 10 getDiscountPrice(2, 10) // 16 getDiscountPrice(3, 10) // 21
State Pattern
)描述:
在状态更改时更改类的行为(方法)
class Discount { constructor () { // 当前状态 this.currentState = '' // 全部状态 this.states = { typeA () { console.log('typeA 1') }, typeB () { console.log('typeB 0.8') }, typeC () { console.log('typeC 0.7') }, } } // 更新当前状态 setState (_currentState) { this.currentState = _currentState return this } // 开始计算 compute () { let currentStateHandler = this.states[this.currentState] currentStateHandler && currentStateHandler() return this } } let discount = new Discount() discount .setState('typeA') .compute() // typeA 1 .setState('typeC') .compute() // typeC 0.7 .setState('typeB') .compute() // typeB 0.8
欢迎关注无广告文章公众号:学前端