JavaScript常用設(shè)計(jì)模式
點(diǎn)上方藍(lán)字關(guān)注公眾號(hào)「前端UpUp」
作者:holyZhengs
來(lái)源:https://segmentfault.com/a/1190000015437592
前言常用的設(shè)計(jì)模式
1. 觀察者模式
一個(gè)目標(biāo)對(duì)象維持著一系列依賴(lài)于它的對(duì)象,將有關(guān)狀態(tài)的任何變更自動(dòng)通知觀察者們。在觀察者模式中,觀察者需要直接訂閱目標(biāo)對(duì)象,觀察者與目標(biāo)對(duì)象之間有一定的依賴(lài)關(guān)系。有4個(gè)重要的概念
目標(biāo)對(duì)象(被觀察者):維護(hù)一組觀察患者,提供管理觀察者的方法。 觀察者:提供一個(gè)更新接口,用于收到通知時(shí),進(jìn)行更新 具體目標(biāo)對(duì)象:代表具體的目標(biāo)對(duì)象 具體觀察者:代表具體的觀察者
// 目標(biāo)對(duì)象
class Subject {
constructor() {
// 觀察者列表
this.observers = []
}
addObserver(observer) {
this.observers.push(observer)
}
removeObserver() {
this.observers.pop()
}
notify() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 觀察者
class Observer {
constructor() {
// 使用時(shí)會(huì)被具體update方法覆蓋
this.update = function () {
// ..
}
}
}
// 具體目標(biāo)對(duì)象
class currentSubject extends Subject {
constructor() {
super()
}
// 其他自定義方法
dosomething() {
console.log('currentSubject change')
this.notify()
}
}
// 具體觀察者
class currentObserver extends Observer {
constructor() {
super()
}
// 重寫(xiě)update
update() {
console.log('change!')
}
}
// 訂閱
let curSubject = new currentSubject()
let curObserver = new currentObserver()
curSubject.addObserver(curObserver)
// 觸發(fā)
curSubject.dosomething()
// currentSubject change
2.發(fā)布/訂閱模式
發(fā)布訂閱模式可以說(shuō)是觀察這模式的一種變體,一種實(shí)現(xiàn)。它使用一個(gè)主題/事件通道,介于發(fā)布者和訂閱者之間,避免了發(fā)布者和訂閱者之間的依賴(lài)關(guān)系。
class PubSub {
constructor() {
// 主題/事件通道
this.topics = {}
}
publish(topic, args) {
if (!this.topics[topic]) {
return
}
let subscribers = this.topics[topic]
subscribers.forEach(subscriber => {
subscriber.updata(args)
})
}
subscribe(topic, subscriber ) {
if (!this.topics[topic]) {
this.topics[topic] = []
}
this.topics[topic].push(subscriber )
}
}
let pubsub = new PubSub()
pubsub.subscribe('one', subscriber )
pubsub.publish('one', 'some args')
3. 工廠模式
工廠函數(shù)提供一個(gè)通用的接口來(lái)創(chuàng)建對(duì)象,我們可以指定我們希望創(chuàng)建的對(duì)象類(lèi)型,我們通知工廠函數(shù)需要什么類(lèi)型的對(duì)象并提供對(duì)應(yīng)的數(shù)據(jù),返回對(duì)應(yīng)的實(shí)例。
class Car {
constructor(options) {
this.doors = options.doors || 4;
this.state = options.state || "brand new";
this.color = options.color || "silver";
}
}
class Truck {
constructor(options) {
this.state = options.state || "used";
this.wheelSize = options.wheelSize || "large";
this.color = options.color || "blue";
}
}
function vehicleFactory (options) {
if (options.type === 'car') {
return new Car(options)
} else {
return new Truck(options)
}
}
何時(shí)使用工廠模式
當(dāng)我們的對(duì)象比較復(fù)雜的時(shí)候。 當(dāng)我們需要根據(jù)不同情況創(chuàng)建不同對(duì)象實(shí)例的時(shí)候。 當(dāng)我們需要?jiǎng)?chuàng)建許多相似對(duì)象的時(shí)候。
缺點(diǎn)
使用不當(dāng)會(huì)增加程序的復(fù)雜度
4. 抽象工廠模式
抽象工廠模式,將對(duì)象的實(shí)現(xiàn)細(xì)節(jié)抽離出來(lái)。適用于需要和多種對(duì)象一起工作的場(chǎng)景。
class Truck {
constructor(options) {
this.state = options.state || "used";
this.wheelSize = options.wheelSize || "large";
this.color = options.color || "blue";
}
}
class Car {
constructor(options) {
this.doors = options.doors || 4;
this.state = options.state || "brand new";
this.color = options.color || "silver";
}
}
class AbstractFactory {
constructor() {
this.types = {}
}
registerFactory(type, factory) {
this.types[type] = factory
}
getInstance(type, args) {
let factory = this.types[type]
if (factory) {
return new factory(args)
}
}
}
let abstractFactory = new AbortController()
abstractFactory.registerFactory('car', Car)
abstractFactory.registerFactory('truck', Truck)
abstractFactory.getInstance('car', options)
abstractFactory.getInstance('truck', options)
5. 單例模式
單例模式限制一個(gè)類(lèi)只有一個(gè)實(shí)例化對(duì)象。
class Obj(data) {
// ....
}
// 利用閉包實(shí)現(xiàn)單例模式,確保obj類(lèi)只有一個(gè)實(shí)例
function singleton (data) {
var instance;
return function () {
if (!instance) {
instance = new Obj(data)
}
return instance
}
}
6. 中介者模式
中介者模式就是提供一個(gè)中心點(diǎn)給系統(tǒng)不同組件之間進(jìn)行通信,降低系統(tǒng)組件之間的耦合程度。
// 實(shí)現(xiàn)與發(fā)布/訂閱模式類(lèi)似
觀察者模式和發(fā)布訂閱模式專(zhuān)注于維護(hù)目標(biāo)對(duì)象和觀察者之間的關(guān)系,當(dāng)主題對(duì)象發(fā)送變化時(shí),通知所有對(duì)改主題感興趣的觀察者。而中介者模式的話(huà),專(zhuān)注于限制對(duì)象的通信必須通過(guò)中介者來(lái)通信。兩者都提倡松耦合。
7. 裝飾者模式
裝飾者模式,通過(guò)一個(gè)裝飾類(lèi)對(duì)現(xiàn)有動(dòng)態(tài)添加行為,以及對(duì)原有行為進(jìn)行裝飾。
// o為已有對(duì)象
var M20 = function(o){ // 這里定義一個(gè)裝飾類(lèi)
var str = '20多歲的時(shí)候,';
// o是傳入的對(duì)象,調(diào)用傳入對(duì)象的方法,加以裝飾
this.eat = function(){
return str + o.eat()+",肥得很!";
};
this.drink = function(){
return str + o.drink()+",就是個(gè)水桶!";
};
this.coding = function(){
return str + o.coding()+",代碼又寫(xiě)得撇!";
};
}
alert(new M20(david).eat()); // 20多歲的時(shí)候,大衛(wèi)是個(gè)大胖子,一天只曉得吃,肥得很!
alert(new M20(david).drink()); // 20多歲的時(shí)候,大衛(wèi)除了吃就是喝,就是個(gè)水桶!
alert(new M20(david).coding()); // 20多歲的時(shí)候,寫(xiě)代碼吧,大衛(wèi),代碼又寫(xiě)得撇!
8. 適配器模式
使用一個(gè)新的接口對(duì)現(xiàn)有的接口進(jìn)行包裝,處理數(shù)據(jù)與接口的不匹配。
function api (x1, x2, x3) {
console.log(x1 + x2 + x3); // 用console.log來(lái)模擬接口的相關(guān)操作
}
var data = {
a: '我',
b: '很',
c: '帥'
}
function adapterApi (o) {
// 通過(guò)適配器函數(shù)來(lái)調(diào)用目的api
api(o.a, o.b, o.c);
}
adapterApi(data);
// 我很帥
學(xué)習(xí)資料:
聽(tīng)飛狐聊JavaScript設(shè)計(jì)模式系列
javascript設(shè)計(jì)模式
感謝大家
關(guān)注「前端UpUp」,分享精選面試熱點(diǎn)文章。
加我好友,一起討論算法,2021一起UpUp。


