Golang - Design Pattern #19: 橋接模式 (Bridge)

更新於 發佈於 閱讀時間約 7 分鐘
raw-image
🌉 將抽象和實現分離 🌉

在許多複雜的程式設計問題中,如何將抽象與其具體實現分離開來,往往是一個重要的挑戰。橋接模式正是為了解決這樣的問題而生。透過橋接模式 (Bridge Pattern),不僅可以確保抽象和實現在結構上分離,還能提供一套彈性的機制來適應變化。接下來,我們將深入探討這一模式,並學習如何在 Go 語言中實現它。


橋接模式

橋接模式的主要目的是"分離抽象與實現",這樣在兩者獨立變化時,不會互相影響。此模式涉及到一個抽象接口,以及多個實現該接口的具體類。這使得你可以在不修改原始抽象類的情況下,更改或添加新的具體實現。


Go to Code ~~

🎨 不同的畫圖方法

假設我們有一個形狀Shape,它有多種不同的繪製方法(如繪製在螢幕上、打印等)。使用橋接模式,我們可以輕鬆地將Shape和繪製方法分離。


package main

import "fmt"

// DrawingAPI is the abstract "implementation" interface
type DrawingAPI interface {
DrawCircle(radius, x, y float64)
}

// Shape is the abstract "abstraction" class
type Shape interface {
Draw()
}

type CircleShape struct {
x, y, radius float64
drawingAPI DrawingAPI
}

func NewCircle(x, y, radius float64, drawingAPI DrawingAPI) *CircleShape {
return &CircleShape{x: x, y: y, radius: radius, drawingAPI: drawingAPI}
}

func (c *CircleShape) Draw() {
c.drawingAPI.DrawCircle(c.radius, c.x, c.y)
}

type DrawingAPI1 struct{}

func (da *DrawingAPI1) DrawCircle(radius, x, y float64) {
fmt.Printf("API1 draws circle at %f:%f radius %f\n", x, y, radius)
}

type DrawingAPI2 struct{}

func (da *DrawingAPI2) DrawCircle(radius, x, y float64) {
fmt.Printf("API2 draws circle at %f:%f radius %f\n", x, y, radius)
}

func main() {
// Usage
circle1 := NewCircle(1, 2, 3, &DrawingAPI1{})
circle1.Draw() // Output: API1 draws circle at 1.000000:2.000000 radius 3.000000

circle2 := NewCircle(1, 2, 3, &DrawingAPI2{})
circle2.Draw() // Output: API2 draws circle at 1.000000:2.000000 radius 3.000000
}


📩 消息發送

假設我們有一個消息發送系統,其中有不同的消息(如緊急消息、普通消息)和多種發送方式(如SMS、Email)。我們可以使用橋接模式將消息和發送方式分離。


package main

import "fmt"

// MessengerAPI is the abstract "implementation" interface
type MessengerAPI interface {
Send(message string, to string)
}

// Message is the abstract "abstraction" class
type Message interface {
Send()
}

type NormalMessage struct {
content string
to string
method MessengerAPI
}

func NewNormalMessage(content, to string, method MessengerAPI) *NormalMessage {
return &NormalMessage{content: content, to: to, method: method}
}

func (m *NormalMessage) Send() {
m.method.Send(m.content, m.to)
}

type UrgentMessage struct {
content string
to string
method MessengerAPI
}

func NewUrgentMessage(content, to string, method MessengerAPI) *UrgentMessage {
return &UrgentMessage{content: content, to: to, method: method}
}

func (m *UrgentMessage) Send() {
m.method.Send("[Urgent]"+m.content, m.to)
}

type SMSMessenger struct{}

func (sms *SMSMessenger) Send(message, to string) {
fmt.Printf("Sending SMS to %s: %s\n", to, message)
}

type EmailMessenger struct{}

func (email *EmailMessenger) Send(message, to string) {
fmt.Printf("Sending Email to %s: %s\n", to, message)
}

func main() {
// Usage
msg1 := NewNormalMessage("Hello, world!", "John", &SMSMessenger{})
msg1.Send() // Output: Sending SMS to John: Hello, world!

msg2 := NewUrgentMessage("System is down!", "Admin", &EmailMessenger{})
msg2.Send() // Output: Sending Email to Admin: [Urgent]System is down!
}


小結

橋接模式為我們提供了一個結構化的方法,幫助我們有效地分離抽象和實現。透過這一模式,我們可以確保當增加新的實現或修改現有實現時,不會對原有的抽象造成影響。而 Go 語言中的接口使得我們可以輕鬆地應用這一模式,創建高度靈活且可維護的代碼。🛠️

avatar-img
31會員
194內容數
歡迎來到【代碼的詩情】:探索程式語言之美 系列,這是一場優雅的程式之旅,透過詩歌的抒發,尋找不同程式語言的美感和精髓。 在這個系列中,我們將透過文字的韻律,深入探索多種程式語言的核心概念和語法,以及它們獨特的應用和技巧。每一篇詩歌都是一個故事,每一段代碼都是一句詩句,讓代碼的旋律和詩情在其中相互交織。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
KH Huang的沙龍 的其他內容
在軟體開發中,處理nil或空值是一個常見的挑戰。不妥當地處理它們可能導致錯誤,使得程式碼的健壯性下降。但有沒有一種方法,可以讓我們在不做特殊檢查的情況下,優雅地處理這些空值呢?答案是肯定的,那就是空物件模式 (Null Object Pattern)!
創建物件有時是一個資源密集型和耗時的過程,尤其是當涉及到從資料庫或其他來源初始化物件時。原型模式就是為了解決這種問題🔧,它提供了一種方法,能夠通過複製一個已存在的物件來迅速創建新物件,而不是從頭開始。
當我們在處理一連串的事件或請求時,責任鏈模式 (Chain of Responsibility Pattern) 就像一位隱形的助手🤖,幫助我們將這些請求一一分發給合適的處理者。
大家有沒有遇到過這種情況:當應用程式使用過多資源,如記憶體或 CPU 時,整個系統的性能直線下降?😰 不得不說,資源的有效管理在軟體開發中真的超級重要!這就是享元模式 (Flyweight Pattern) 大顯身手的時候了!
你知道那種感覺嗎?當你想從複雜的家電系統中只開啟你的電視和音響,卻需要找一大堆遙控器才能完成。外觀模式(Facade)就是這樣的解決方案!它可以幫助我們簡化複雜系統的操作,提供一個單一、簡單的接口。
你還記得在學校時代,當兩位朋友吵架時,有時會有第三者出來做調解嗎?在程式設計中,我們有一種模式就像那位調解者,幫助兩個物件之間保持距離,這就是仲介者模式( Mediator Pattern )!
在軟體開發中,處理nil或空值是一個常見的挑戰。不妥當地處理它們可能導致錯誤,使得程式碼的健壯性下降。但有沒有一種方法,可以讓我們在不做特殊檢查的情況下,優雅地處理這些空值呢?答案是肯定的,那就是空物件模式 (Null Object Pattern)!
創建物件有時是一個資源密集型和耗時的過程,尤其是當涉及到從資料庫或其他來源初始化物件時。原型模式就是為了解決這種問題🔧,它提供了一種方法,能夠通過複製一個已存在的物件來迅速創建新物件,而不是從頭開始。
當我們在處理一連串的事件或請求時,責任鏈模式 (Chain of Responsibility Pattern) 就像一位隱形的助手🤖,幫助我們將這些請求一一分發給合適的處理者。
大家有沒有遇到過這種情況:當應用程式使用過多資源,如記憶體或 CPU 時,整個系統的性能直線下降?😰 不得不說,資源的有效管理在軟體開發中真的超級重要!這就是享元模式 (Flyweight Pattern) 大顯身手的時候了!
你知道那種感覺嗎?當你想從複雜的家電系統中只開啟你的電視和音響,卻需要找一大堆遙控器才能完成。外觀模式(Facade)就是這樣的解決方案!它可以幫助我們簡化複雜系統的操作,提供一個單一、簡單的接口。
你還記得在學校時代,當兩位朋友吵架時,有時會有第三者出來做調解嗎?在程式設計中,我們有一種模式就像那位調解者,幫助兩個物件之間保持距離,這就是仲介者模式( Mediator Pattern )!
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
各位伙伴早安,上回分享如何圖解具體資訊 今天來談談抽象的概念、理論等訊息要如何圖解吧~ 這也是我覺得是視覺筆記最有價值且可以發揮的地方   相比具體資訊,抽象資訊不但沒有標準答案(就算有,也不代表每個人的理解相同),因此具像化的難度與意義就更高了,而用畫圖表達抽象概念有三個主要目的,依據目的
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
※ 工廠模式 定義: 工廠模式是一種實現了「工廠」概念的物件導向設計模式。它提供一個通用的工廠介面,將創建instance(實例)的程式碼交由子類別各自實現,並根據需求去動態地生成相應的物件。這種模式將物件的創建邏輯與使用邏輯分開,使程式碼更容易維護和擴展。 特點: 具有高度標準化和同質性的
※ 單例模式介紹 ※ 定義:單例模式是一種設計模式,確保一個class(類)只有一個實例,並提供一個存取它的全域存取點。無論如何取值,皆只對這個實例取值。 ※ 目的:保證一個類別只會產生一個物件,而且提供存取該物件的統一方法。 ※ 講解:單例模式確保一個類無論怎麼 new 或 get,都只能拿
Thumbnail
網格擴散可以就像剪紙一樣,把紙上想要的部分剪下來。 通過模型的一個點,找到周圍相鄰的點;其他點又能找到周圍相鄰的點,就像水波一樣擴散出去。 許多3D的算法,如裁切、干涉深度偵測等都會用到。
多型性(polymorphism)是物件導向中的一個重要概念,它指的是同一個方法或函式在不同的物件類別中可以有不同的行為。在 Python 中,多型性通常是通過繼承和方法重寫(method overriding)來實現的。 主要是為了不同資料類型的實體提供統一的介面,我們藉由下面的程式範例來多理解
Thumbnail
在物件導向程式設計的進階階段,學生將學習繼承、介面、抽象類別等核心概念。繼承允許類別共享屬性和方法,介面確保實現類別提供特定的方法實現,而抽象類別定義了基本結構供子類別擴展。這些知識點有助於提升程式碼的重用性、擴展性和維護性。
對於程序式編程來說,程式是由一系列的指令組成,例如計算數值、印出訊息、修改變數、呼叫子程序、配置變數的記憶體空間等。定義函式是為了讓一些程序可以重複利用,因此稱為子程序,其中參數為子程序中特別的變數,讓我們能夠透過它們控制子程序的行為。函式的回傳值只是一種方便將結果帶回來的方法,但一般只能回傳一個值
Thumbnail
本文介紹創造想像發展技巧單元「結合體」,是結合另外物件的功能或特性來增加創意。 若想創新一樣東西,至少要找兩個以上的被結合物,依照結合矩陣表格與七個步驟,逐步構思後將結合矩陣每一格都填滿,以產生新的設計構想。最後使用創新機會/產品的表格,填寫新構想的命名、結合進來後新構想的功能、新構想的特色與限制。
讓我在這篇文章總結一下前面對物件導向設計的討論,我們討論了物件導向的四個特性:繼承、抽象、多型、封裝,分析了它們的問題,並跟函數式編程的思維做比較。我們引入了與之相對應的特性:泛型、特性系統、模組化,有些特性雖然跟那四個特性很像,但在一些細微的地方有不同的詮釋,使得整體思考方式很不一樣。 「繼
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
各位伙伴早安,上回分享如何圖解具體資訊 今天來談談抽象的概念、理論等訊息要如何圖解吧~ 這也是我覺得是視覺筆記最有價值且可以發揮的地方   相比具體資訊,抽象資訊不但沒有標準答案(就算有,也不代表每個人的理解相同),因此具像化的難度與意義就更高了,而用畫圖表達抽象概念有三個主要目的,依據目的
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
※ 工廠模式 定義: 工廠模式是一種實現了「工廠」概念的物件導向設計模式。它提供一個通用的工廠介面,將創建instance(實例)的程式碼交由子類別各自實現,並根據需求去動態地生成相應的物件。這種模式將物件的創建邏輯與使用邏輯分開,使程式碼更容易維護和擴展。 特點: 具有高度標準化和同質性的
※ 單例模式介紹 ※ 定義:單例模式是一種設計模式,確保一個class(類)只有一個實例,並提供一個存取它的全域存取點。無論如何取值,皆只對這個實例取值。 ※ 目的:保證一個類別只會產生一個物件,而且提供存取該物件的統一方法。 ※ 講解:單例模式確保一個類無論怎麼 new 或 get,都只能拿
Thumbnail
網格擴散可以就像剪紙一樣,把紙上想要的部分剪下來。 通過模型的一個點,找到周圍相鄰的點;其他點又能找到周圍相鄰的點,就像水波一樣擴散出去。 許多3D的算法,如裁切、干涉深度偵測等都會用到。
多型性(polymorphism)是物件導向中的一個重要概念,它指的是同一個方法或函式在不同的物件類別中可以有不同的行為。在 Python 中,多型性通常是通過繼承和方法重寫(method overriding)來實現的。 主要是為了不同資料類型的實體提供統一的介面,我們藉由下面的程式範例來多理解
Thumbnail
在物件導向程式設計的進階階段,學生將學習繼承、介面、抽象類別等核心概念。繼承允許類別共享屬性和方法,介面確保實現類別提供特定的方法實現,而抽象類別定義了基本結構供子類別擴展。這些知識點有助於提升程式碼的重用性、擴展性和維護性。
對於程序式編程來說,程式是由一系列的指令組成,例如計算數值、印出訊息、修改變數、呼叫子程序、配置變數的記憶體空間等。定義函式是為了讓一些程序可以重複利用,因此稱為子程序,其中參數為子程序中特別的變數,讓我們能夠透過它們控制子程序的行為。函式的回傳值只是一種方便將結果帶回來的方法,但一般只能回傳一個值
Thumbnail
本文介紹創造想像發展技巧單元「結合體」,是結合另外物件的功能或特性來增加創意。 若想創新一樣東西,至少要找兩個以上的被結合物,依照結合矩陣表格與七個步驟,逐步構思後將結合矩陣每一格都填滿,以產生新的設計構想。最後使用創新機會/產品的表格,填寫新構想的命名、結合進來後新構想的功能、新構想的特色與限制。
讓我在這篇文章總結一下前面對物件導向設計的討論,我們討論了物件導向的四個特性:繼承、抽象、多型、封裝,分析了它們的問題,並跟函數式編程的思維做比較。我們引入了與之相對應的特性:泛型、特性系統、模組化,有些特性雖然跟那四個特性很像,但在一些細微的地方有不同的詮釋,使得整體思考方式很不一樣。 「繼