橋接模式(Bridge Pattern):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱爲柄體(Handle and Body)模式或接口(Interface)模式。
在橋接模式結構圖中包含如下幾個角色:
-
Abstraction(抽象類):用於定義抽象類的接口,它一般是抽象類而不是接口,其中定義了一個 Implementor(實現類接口)類型的對象並可以維護該對象,它與 Implementor 之間具有關聯關係,它既可以包含抽象業務方法,也可以包含具體業務方法。
-
RefinedAbstraction(擴充抽象類):擴充由 Abstraction 定義的接口,通常情況下它不再是抽象類而是具體類,它實現了在 Abstraction 中聲明的抽象業務方法,在 RefinedAbstraction 中可以調用在 Implementor 中定義的業務方法。
-
Implementor(實現類接口):定義實現類的接口,這個接口不一定要與 Abstraction 的接口完全一致,事實上這兩個接口可以完全不同,一般而言,Implementor 接口僅提供基本操作,而 Abstraction 定義的接口可能會做更多更復雜的操作。Implementor 接口對這些基本操作進行了聲明,而具體實現交給其子類。通過關聯關係,在 Abstraction 中不僅擁有自己的方法,還可以調用到 Implementor 中定義的方法,使用關聯關係來替代繼承關係。
-
ConcreteImplementor(具體實現類):具體實現 Implementor 接口,在不同的 ConcreteImplementor 中提供基本操作的不同實現,在程序運行時,ConcreteImplementor 對象將替換其父類對象,提供給抽象類具體的業務操作方法。
應用場景
假設我們開了一家咖啡店,用戶可以選擇不同大小的咖啡,可以選擇加奶或者加糖,如果用普通的繼承結構會變成如下的樣子。
這時客戶要求還想要加蜂蜜的咖啡,有的客戶又想要特大號咖啡,隨着種類的增加類的總類也在增加,最後會發現我們會有杯子大小種類x配料種類的個數的類。
爲了解決會出現如此多類的問題,這裏是用橋接模式來簡化結構。
其中ICoffee作爲抽象類,提供了OrderCoffee
的方法, 並保有一個實現類方法的實例,具體實現方法大杯(LargeCoffee
)和小杯(SmallCoffee
)分別實現了自己的OrderCoffee
方法,配料Sugar和Milk則作爲具體實現類被附在抽象類上
具體實現
package bridge
import "fmt"
type ICoffee interface {
OrderCoffee(count int)
}
type LargeCoffee struct {
additives ICoffeeAdditives
}
func (l *LargeCoffee) OrderCoffee(count int) {
fmt.Print("Large Coffee ")
l.additives.AddAdditives()
fmt.Println(count, " cup")
}
type SmallCoffee struct {
additives ICoffeeAdditives
}
func (s *SmallCoffee) OrderCoffee(count int) {
fmt.Print("Small Coffee ")
s.additives.AddAdditives()
fmt.Println(count, "cup")
}
type ICoffeeAdditives interface {
AddAdditives()
}
type Milk struct{}
func (m *Milk) AddAdditives() {
fmt.Print("With Milk ")
}
type Sugar struct{}
func (s *Sugar) AddAdditives() {
fmt.Print("With Sugar ")
}
測試代碼
package bridge
import (
"testing"
)
func TestPrintAPI1(t *testing.T) {
largeCoffeeMilk := LargeCoffee{
additives: &Milk{},
}
largeCoffeeMilk.OrderCoffee(1)
smallCoffeeMilk := SmallCoffee{
additives: &Milk{},
}
smallCoffeeMilk.OrderCoffee(1)
largeCoffeeSugar := LargeCoffee{
additives: &Sugar{},
}
largeCoffeeSugar.OrderCoffee(1)
smallCoffeeMSugar := SmallCoffee{
additives: &Sugar{},
}
smallCoffeeMSugar.OrderCoffee(1)
}
=== RUN TestPrintAPI1
Large Coffee With Milk 1 cup
Small Coffee With Milk 1 cup
Large Coffee With Sugar 1 cup
Small Coffee With Sugar 1 cup
--- PASS: TestPrintAPI1 (0.00s)
PASS