Go設計模式--中介者,最后的模式!
大家好,這里是每周都在陪你一起進步的網管~!今天繼續學習設計模式,也是我們要學習的最后一個設計模式—中介者模式,對這個模式有一點了解后會覺得它跟我們已經學過的觀察者模式挺像,但是兩者還是有些區別的,使用場景也不一樣,具體我們放在最后再講,先來一起學習中介者模式。
中介者模式是一種行為設計模式, 能讓程序減少對象之間混亂無序的依賴關系。 該模式會限制對象之間的直接交互, 迫使它們通過一個中介者對象進行交互。
中介者模式使修改、擴展和重用單個組件變得容易,因為它們不再依賴于所有其他類。下面我們舉一個簡單的例子來說明怎么在程序里使用中介者模式減少各個組件類之間的耦合。
在現實生活中,機場的控制塔是一個典型的中介者角色, 飛機在起飛和降落前都會向控制塔發出問詢,控制塔會給飛機發送指令協調它們的起飛降落時間,避免造成事故。
現在假設一個機場只有一條跑道,即同一時刻只能承載一架飛機的起飛和降落,飛機和飛機之間不能直接溝通,這樣就亂套了,必須由控制塔作為一個中介者向各個飛機(組件)同步跑道的可用狀態。
下面我們先來定義飛機和指揮塔--即組件和中介者的 Interface 接口。
"本文使用的完整可運行源碼
去公眾號「網管叨bi叨」發送【設計模式】即可領取"
// 中介者--機場指揮塔的接口定義
type mediator interface {
canLanding(airplane airplane) bool
notifyAboutDeparture()
}
// 組件--飛行器的接口定義
type airplane interface {
landing()
takeOff()
permitLanding()
}
接下來我們來實現具體的組件,這里提供兩個組件作為演示,一架波音飛機和一架空客飛機。
每個飛機在降落landing方法里都會去跟作為中介者的指揮塔發出問詢,看是否能夠降落,如果跑道正在被占用,那么會等待指揮塔調用它自己的permitLanding()通知可以降落后再降落。而其他占用跑道的飛機在起飛后會通過中介者提供的notifyAboutDeparture() 告知指揮塔自己的離去。
具體的代碼如下:
"本文使用的完整可運行源碼
去公眾號「網管叨bi叨」發送【設計模式】即可領取"
// 組件1--波音飛機
type boeingPlane struct {
mediator
}
func (b *boeingPlane) landing() {
if !b.mediator.canLanding(b) {
fmt.Println("Airplane Boeing: 飛機跑到正在被占用,無法降落!")
return
}
fmt.Println("Airplane Boeing: 已成功降落!")
}
func (b *boeingPlane)takeOff() {
fmt.Println("Airplane Boeing: 正在起飛離開跑道!")
b.mediator.notifyAboutDeparture()
}
func (b *boeingPlane)permitLanding() {
fmt.Println("Airplane Boeing: 收到指揮塔信號,允許降落,正在降落!")
b.landing()
}
// 組件2--空客飛機
type airBusPlane struct {
mediator mediator
}
func (airbus *airBusPlane) landing() {
if !airbus.mediator.canLanding(airbus) {
fmt.Println("Airplane AirBus: 飛機跑到正在被占用,無法降落!")
return
}
fmt.Println("Airplane AirBus: 已成功降落!")
}
func (airbus *airBusPlane) takeOff() {
fmt.Println("Airplane AirBus: 正在起飛離開跑道!")
airbus.mediator.notifyAboutDeparture()
}
func (airbus *airBusPlane)permitLanding() {
fmt.Println("Airplane AirBus: 收到指揮塔信號,允許降落,正在降落!")
airbus.landing()
}
作為中介者的指揮塔,提供兩個方法
- canLanding:提供給飛機組件問詢是否可以降落的方法,如果不可以會把飛機加入到等待隊列中,后續跑道空閑后會進行通知。
- notifyAboutDeparture:提供給占用跑道的飛機通知指揮塔已起飛,指揮塔會向排隊降落的飛機中的首位發送降落指令--調用飛機對象的permitLanding方法
"本文使用的完整可運行源碼
去公眾號「網管叨bi叨」發送【設計模式】即可領取"
// 中介者實現--指揮塔
type manageTower struct {
isRunwayFree bool
airportQueue []airplane
}
func (tower *manageTower) canLanding(airplane airplane) bool {
if tower.isRunwayFree {
// 跑道空閑,允許降落,同時把狀態變為繁忙
tower.isRunwayFree = false
return true
}
// 跑道繁忙,把飛機加入等待通知的隊列
tower.airportQueue = append(tower.airportQueue, airplane)
return false
}
func (tower *manageTower) notifyAboutDeparture() {
if !tower.isRunwayFree {
tower.isRunwayFree = true
}
if len(tower.airportQueue) > 0 {
firstPlaneInWaitingQueue := tower.airportQueue[0]
tower.airportQueue = tower.airportQueue[1:]
firstPlaneInWaitingQueue.permitLanding()
}
}
func newManageTower() *manageTower {
return &manageTower{
isRunwayFree: true,
}
}
這樣我們就可以通過指揮塔,協調多個飛機使用飛機場跑道進行有序的起飛和降落了。
"本文使用的完整可運行源碼
去公眾號「網管叨bi叨」發送【設計模式】即可領取"
func main() {
tower := newManageTower()
boeing := &boeingPlane{
mediator: tower,
}
airbus := &airBusPlane{
mediator: tower,
}
boeing.landing()
airbus.landing()
boeing.takeOff()
}
執行程序后,會有類似下面的輸出:
本文的完整源碼,已經同步收錄到我整理的電子教程里啦,可向我的公眾號「網管叨bi叨」發送關鍵字【設計模式】領取。
看完例子對中介者模式有了一定了解后我們接下來再詳細說說它的構成以及用代碼實現中介者模式的步驟。
中介者模式的構成
中介者模式的結構構成可以用下面的UML類圖來表示
圖中的各個類的構成跟我們上面代碼實例中列舉的十分類似,Component 實現類里需要持有指向中介者的引用,中介者里也保有對各個組件對象的引用,只不過示例里是把組件保存在一個列表里,UML 中是把各個組件單獨保存在了中介者的屬性里。
下面我們再把用代碼實現中介者模式的步驟簡單敘述一遍:
- 定義一組會相互調用,擁有強耦合的組件。
- 指定中介者接口以及中介者與各個組件之間的通信方式。在大多數情況下中介者接口中必須有一個Notify/Notification方法從組件接收通知。
- 創建具體中介者實現,該實現將會存儲其管理的所有Component對象的引用
- 組件對象應該保存中介者的引用,如果想在不同上下文下使用不同的中介者實現,那么應該通過中介者接口類型保存對具體中介者的引用。
- 將組件對象調用其他組件對象的方法提煉到中介者中,組件對象調用中介者的通知方法,由中介者再去調用相對應的組件的方法,從而完成組件與組件間的解耦。
中介模式與觀察者模式區別
中介模式與觀察者模式在結構上有些相似,觀察者模式中的EventDispatcher 和 中介模式中的 Mediator 看起來很想,都是把多個組件之間的關系,維護到自身,實現組件間的間接通信達到解構效果,不過這兩個設計模式在使用場景或者叫要解決的問題上,還是有些差別
- 觀察者模式
組件間的溝通是單向的,從被觀察(發送事件的實體)到觀察者(監聽器),一個參與者要么是觀察者要么是被觀察者,不會同時兼具兩種身份。
- 中介模式
參與者之間可以雙向溝通,當參與者之間關系復雜維護成本很高的時候可以考慮中介模式。
總結
中介者模式(Mediator Pattern)又叫作調解者模式或調停者模式。 用一個中介對象封裝一系列對象交互, 中介者使各對象不需要顯式地相互作用, 從而使其耦合松散, 而且可以獨立地改變它們之間的交互, 屬于行為型設計模式。
中介者模式主要適用于以下應用場景。
- 系統中對象之間存在復雜的引用關系,產生的相互依賴關系結構混亂且難以理解。
- 交互的公共行為,如果需要改變行為,則可以增加新的中介者類。
中介者模式的優點
- 減少類間依賴,將多對多依賴轉化成一對多,降低了類間耦合。
- 類間各司其職,符合迪米特法則。
中介者模式的缺點
- 中介者模式將原本多個對象直接的相互依賴變成了中介者和多個組件類的依賴關系。
- 當組件類越多時,中介者就會越臃腫,變得復雜且難以維護。
最后
今天這篇完結后,用Go學設計模式就正式更新完了,算是一個小小的成就,大家可以在專輯鏈接里查看系列里的其他文章,后面會寫篇總結把設計模式的學習心法給大家說一說,其實就是多看,多練,除此之外也有點小技巧,咱們放到后面給系列收尾時再說。