設計模式與程式架構(六)

閱讀時間約 8 分鐘

※ 觀察者模式

定義:

  • 觀察者模式(Observer Pattern)是一種設計模式,涉及兩個主要角色:觀察者(Observers)和被觀察者(Subject)。在這種模式中,一群觀察者訂閱並觀察某個被觀察的對象。當被觀察者的狀態發生改變時,它會通知所有觀察者,讓他們知曉並作出相應的反應。這種模式通過訂閱和觀察機制實現了對象間的鬆散耦合,使得狀態更新能夠高效地傳遞給所有相關的觀察者。
  • 觀察者模式的工作流程如下:
  1. Subject(被觀察者): 它是被觀察的對象,持有一個觀察者列表(Observers),當自身狀態改變時,會通知這些觀察者。
  2. Observer(觀察者): 它們是對Subject感興趣的對象,會訂閱(觀察)Subject的變化。
  3. 訂閱/取消訂閱: Observer可以訂閱(附加到觀察者列表)或取消訂閱(從觀察者列表移除)。
  4. 通知更新: 當Subject的狀態發生變化時,它會遍歷觀察者列表,通知所有觀察者進行更新。


好處是:

  • 高效通知:比起觀察者每隔一段時間詢問被觀察者是否有更新,讓被觀察者在更新時直接通知觀察者更加有效率,解決了輪詢(polling)這種低效的問題。
  • 降低耦合度:利用訂閱和通知機制,使得程式的關注點從觀察者分離出來,減少了被觀察者與觀察者之間的耦合度,提升了程式碼的可維護性和靈活性。
  • 耦合度:指的是物件跟物件之間參雜在一起的程度。

使用場景:觀察者模式能有效地解決多對一或多對多對象之間的通信問題,提升系統的靈活性和可擴展性。

  • 事件處理系統當某個事件發生時,需要通知多個觀察者。例如UI元件的按鈕點擊事件。
  • 數據更新通知:當某個資料源發生變化時,需要通知相關的觀察者自動更新。例如新聞應用程式中,當新聞內容更新時通知訂閱者。
  • 跨系統通信:當某個服務狀態改變或有重要事件時,通知其他相關服務。
  • 聊天室或論壇應用:在實時通訊應用中,當有新的消息發送時,需要通知所有在線的用戶。

觀察者模式基本架構範例解說:

//定義觀察者該有的東西,在觀察者模式中習慣用Observer作為關鍵字。
class Observer {
// 唯一標識觀察者的 ID
id: string
//希望每個被創造出來的觀察者都是獨一無二,所以需要id並且用random方式產出
constructor() {
this.id = String(~(Math.random() * 1000)).padStart(3, "0")
}
/**
*用於當 subject 發布消息時,接收消息
* @param data any- 任意類型,保有 subject 發布的消息內容
*/
update = (data: any) => {
console.log(`觀察者 ${this.id} 收到更新消息瘩內容 : ${data}`)
}
}

//定義被觀察者該有的東西
class Subject {
//定義一個私有的佇列屬性
private queue = <Observer[]>[]

//註冊觀察者,需要一個註冊用的接口
register = (observer: Observer) => {
this.queue.push(observer)
}
//移除觀察者
/**
* 移除觀察者
* @param observer - Observer 類型的觀察者對象
*/
remove = (observer: Observer) => {
const queue = this.queue //將 this.queue 存儲到一個局部變數 queue 中,方便後續操作。
let len = queue.length //表示佇列的長度。
//循環遍歷佇列中的每個元素。
for (let i = 0; i < len; i++) {
//判斷當前元素是否是要移除的觀察者
if (queue[i] === observer) {
queue.splice(i, 1) // 從佇列中移除當前元素。
}
}
}
//通知觀察者
/**
* 通知所有註冊的觀察者
* @param data - 任意類型,保有 subject 發布的消息內容
*/
notify = (data: any) => {
// 使用 forEach 方法遍歷 this.queue 中的每個觀察者(observer)
// 對每個觀察者調用其 update 方法,並將 data 作為參數傳遞過去
this.queue.forEach((observer) => observer.update(data))
}
}
//建立主題
const subject = new Subject()

//建立觀察者
const observer1 = new Observer()
const observer2 = new Observer()
const observer3 = new Observer()
const observer4 = new Observer()
const observer5 = new Observer()

//註冊主題
subject.register(observer1)
subject.register(observer2)
subject.register(observer3)
subject.register(observer4)
subject.register(observer5)
//通知觀察者
subject.notify("更新內容" + "hello world")
/**印出
觀察者 -127 收到更新消息瘩內容 : 更新內容hello world
觀察者 -878 收到更新消息瘩內容 : 更新內容hello world
觀察者 -835 收到更新消息瘩內容 : 更新內容hello world
觀察者 -249 收到更新消息瘩內容 : 更新內容hello world
觀察者 -770 收到更新消息瘩內容 : 更新內容hello world
*/

※ 補充說明:

佇列(Queue)【kyoo】是什麼?

佇列(Queue)是一種資料結構,具有先進先出(FIFO, First In First Out)的特性。簡單來說,這意味著最先加入佇列的元素會最先被移除。

我們可以把佇列想像成排隊的場景。比如在餐廳排隊點餐,先來的人會先排隊,然後他們會先點餐並離開隊伍。後來的人則會排到隊伍的尾端,依序等待自己的順序。

這個特性在現實生活中經常出現,例如排隊買票、排隊取號等。佇列通常使用陣列或鏈結串列(Linked list)來實現。

javascript 底層機制:

在 JavaScript 中,佇列是一種重要的資料結構,因為 JavaScript 是單執行緒的程式。這就像一家餐廳只有一位店員在服務所有顧客。如果有一個非常耗時的任務獨佔了這位店員,其他顧客就會被迫等待,導致整個系統(網頁)卡住,使用者體驗會很差。

為了解決這個問題,可以使用佇列來管理這些任務。當有需要等待回應的任務時,不需要讓店員(執行緒)一直等著,而是可以先去服務其他顧客(處理其他任務),把這個需要等待的任務記到佇列裡,等稍後再回來處理。

例如:在電影院排隊買電影票的過程。

  • 排隊買票:你和其他人排隊等著買電影票。這就像佇列,先來的人先買票,後來的人排在後面。
  • 服務過程:售票員一次只能處理一個顧客。如果你需要選擇座位並且花了一些時間,那麼售票員會記下你的訂單,告訴你「選好座位再來取票」,然後繼續為其他顧客售票。

這樣一來,售票員就不會因為一個需要時間的顧客而讓整個隊伍卡住,其他顧客也可以快速買到票,整個過程就更有效率。

結論:

佇列是一種資料結構,適合處理需要按照先進先出順序執行的任務。它不僅像排隊買電影票那樣處理多人的需求,也能有效地安排和管理程式中的各種執行順序。


    全端網頁開發專業知識分享
    留言0
    查看全部
    發表第一個留言支持創作者!
    ※ 工廠模式 定義: 工廠模式是一種實現了「工廠」概念的物件導向設計模式。它提供一個通用的工廠介面,將創建instance(實例)的程式碼交由子類別各自實現,並根據需求去動態地生成相應的物件。這種模式將物件的創建邏輯與使用邏輯分開,使程式碼更容易維護和擴展。 特點: 具有高度標準化和同質性的
    ※ 單例模式介紹 ※ 定義:單例模式是一種設計模式,確保一個class(類)只有一個實例,並提供一個存取它的全域存取點。無論如何取值,皆只對這個實例取值。 ※ 目的:保證一個類別只會產生一個物件,而且提供存取該物件的統一方法。 ※ 講解:單例模式確保一個類無論怎麼 new 或 get,都只能拿
    ※ 設計模式的五大精神介紹(S.O.L.I.D): ※ 第一大精神 — S:單一職責原則(Single responsibility principle, SRP) ※ 定義: 每個物件,不管是類別或函數,都應該只負責一項功能。 當需求改變時,僅需改相關的區域,而不需要更動其他不相關的部分
    ※ TypeScript範例說明: interface ITest { test1: string test2: number print: (arg: string[]) => boolean } class Test implements ITest { public te
    ※ 何謂Typescript? Typescript是Microsoft開發出來的一種JavaScript的擴展程式語言。 ※ 為什麼選擇 TypeScript? 靜態型別: 在執行程式碼之前就能避免許多錯誤。 幫助開發人員更快發現型別使用上的問題。 有效提升開發應用程式的效率。 輕鬆
    ※ OPP第三大核心-多型 ※ 多型的基本定義: 多型是利用繼承的特性,讓不同的子類別可以實現相同的介面,但在呼叫這些介面的方法時會表現出不同的行為。這使得程式設計更具彈性和擴展性,避免了複雜的條件判斷式,同時促進了代碼的重用。 class Animal { makeSound() {
    ※ 工廠模式 定義: 工廠模式是一種實現了「工廠」概念的物件導向設計模式。它提供一個通用的工廠介面,將創建instance(實例)的程式碼交由子類別各自實現,並根據需求去動態地生成相應的物件。這種模式將物件的創建邏輯與使用邏輯分開,使程式碼更容易維護和擴展。 特點: 具有高度標準化和同質性的
    ※ 單例模式介紹 ※ 定義:單例模式是一種設計模式,確保一個class(類)只有一個實例,並提供一個存取它的全域存取點。無論如何取值,皆只對這個實例取值。 ※ 目的:保證一個類別只會產生一個物件,而且提供存取該物件的統一方法。 ※ 講解:單例模式確保一個類無論怎麼 new 或 get,都只能拿
    ※ 設計模式的五大精神介紹(S.O.L.I.D): ※ 第一大精神 — S:單一職責原則(Single responsibility principle, SRP) ※ 定義: 每個物件,不管是類別或函數,都應該只負責一項功能。 當需求改變時,僅需改相關的區域,而不需要更動其他不相關的部分
    ※ TypeScript範例說明: interface ITest { test1: string test2: number print: (arg: string[]) => boolean } class Test implements ITest { public te
    ※ 何謂Typescript? Typescript是Microsoft開發出來的一種JavaScript的擴展程式語言。 ※ 為什麼選擇 TypeScript? 靜態型別: 在執行程式碼之前就能避免許多錯誤。 幫助開發人員更快發現型別使用上的問題。 有效提升開發應用程式的效率。 輕鬆
    ※ OPP第三大核心-多型 ※ 多型的基本定義: 多型是利用繼承的特性,讓不同的子類別可以實現相同的介面,但在呼叫這些介面的方法時會表現出不同的行為。這使得程式設計更具彈性和擴展性,避免了複雜的條件判斷式,同時促進了代碼的重用。 class Animal { makeSound() {
    你可能也想看
    Google News 追蹤
    Thumbnail
    接下來第二部分我們持續討論美國總統大選如何佈局, 以及選前一週到年底的操作策略建議 分析兩位候選人政策利多/ 利空的板塊和股票
    Thumbnail
    🤔為什麼團長的能力是死亡筆記本? 🤔為什麼像是死亡筆記本呢? 🤨作者巧思-讓妮翁死亡合理的幾個伏筆
    VIPER(View Interactor Presenter Entities Router) View 負責顯示資料。 Interactor 負責管理model。 Presenter 負責處理View的業務邏輯。 Entities 負責data model。
    MVVMC(Model View ViewModel Coordinator),特點是Coordinator。 Model 負責儲存應用程式的資料。 View 負責顯示資料。 ViewModel 負責處理View和Model之間的狀態關係。 Coordinator 負
    MVI(Model View Intent),特點是Intent。 Model 負責介面狀態 View 負責顯示資料。 Intent 負責將封裝後的操作告知Model。
    MVVM(Model View ViewModel),特點是View跟ViewModel之間做資料綁定。 Model 負責儲存應用程式的資料。 View 負責顯示資料。 ViewModel 負責處理View和Model之間的狀態關係。
    MVP(Model View Presenter)由MVC演變而來。MVC與MVP的差異是View跟Model之間的關係;MVC中是可以直接溝通的;MVP中是不可以直接溝通的,必須要透過 Presenter。 Model 負責資料存取。 View 負責顯示資料,並將使用者的操作傳給P
    Thumbnail
    代理模式通過封裝原始對象來實現對該對象的控制和管理,同時不改變原始對象的行為或客戶端與該對象互動的方式,以此介入或增強對該對象的訪問和操作。
    Thumbnail
    策略模式將多種演算法封裝於獨立的策略類別中,每個策略類別都實現了一個共同的介面。這種設計允許使用者在系統運行時動態選擇和切換演算法,以達成相同的目的。
    MVC是一種物件導向設計模式,將應用程式分成Model、View和Controller。是在1979年被提出,主要是要解決下列問題: 維護「長存儲存媒體」(Persistent Storage)的資料 維護執行流程的邏輯控制 顯示使用者所需的資訊和使用介面 Model 實作儲存應用程式
    Thumbnail
    所有的 CSS 設計模式都是為了維持可讀性、好維護、易擴充這幾個目標,今天就來談談 BEM 設計模式,並搭配 Sass 中的 SCSS 來介紹,並探討在各種情境下該如何使用 BEM。
    Thumbnail
    小心設計模式別亂用 📷 介紹 設計模式就是過去的人,根據常見的軟體設計的問題,提出的解決方案。 設計模式總共有23種,根據情境分成三大類型,建立型、結構型、行為型。 建立型模式(Creational Patterns) 簡單工廠(Simple Factory) 工廠方法(Factory) 抽象工廠
    Thumbnail
    接下來第二部分我們持續討論美國總統大選如何佈局, 以及選前一週到年底的操作策略建議 分析兩位候選人政策利多/ 利空的板塊和股票
    Thumbnail
    🤔為什麼團長的能力是死亡筆記本? 🤔為什麼像是死亡筆記本呢? 🤨作者巧思-讓妮翁死亡合理的幾個伏筆
    VIPER(View Interactor Presenter Entities Router) View 負責顯示資料。 Interactor 負責管理model。 Presenter 負責處理View的業務邏輯。 Entities 負責data model。
    MVVMC(Model View ViewModel Coordinator),特點是Coordinator。 Model 負責儲存應用程式的資料。 View 負責顯示資料。 ViewModel 負責處理View和Model之間的狀態關係。 Coordinator 負
    MVI(Model View Intent),特點是Intent。 Model 負責介面狀態 View 負責顯示資料。 Intent 負責將封裝後的操作告知Model。
    MVVM(Model View ViewModel),特點是View跟ViewModel之間做資料綁定。 Model 負責儲存應用程式的資料。 View 負責顯示資料。 ViewModel 負責處理View和Model之間的狀態關係。
    MVP(Model View Presenter)由MVC演變而來。MVC與MVP的差異是View跟Model之間的關係;MVC中是可以直接溝通的;MVP中是不可以直接溝通的,必須要透過 Presenter。 Model 負責資料存取。 View 負責顯示資料,並將使用者的操作傳給P
    Thumbnail
    代理模式通過封裝原始對象來實現對該對象的控制和管理,同時不改變原始對象的行為或客戶端與該對象互動的方式,以此介入或增強對該對象的訪問和操作。
    Thumbnail
    策略模式將多種演算法封裝於獨立的策略類別中,每個策略類別都實現了一個共同的介面。這種設計允許使用者在系統運行時動態選擇和切換演算法,以達成相同的目的。
    MVC是一種物件導向設計模式,將應用程式分成Model、View和Controller。是在1979年被提出,主要是要解決下列問題: 維護「長存儲存媒體」(Persistent Storage)的資料 維護執行流程的邏輯控制 顯示使用者所需的資訊和使用介面 Model 實作儲存應用程式
    Thumbnail
    所有的 CSS 設計模式都是為了維持可讀性、好維護、易擴充這幾個目標,今天就來談談 BEM 設計模式,並搭配 Sass 中的 SCSS 來介紹,並探討在各種情境下該如何使用 BEM。
    Thumbnail
    小心設計模式別亂用 📷 介紹 設計模式就是過去的人,根據常見的軟體設計的問題,提出的解決方案。 設計模式總共有23種,根據情境分成三大類型,建立型、結構型、行為型。 建立型模式(Creational Patterns) 簡單工廠(Simple Factory) 工廠方法(Factory) 抽象工廠