Посередник — це поведінковий патерн, який спрощує комунікацію між компонентами системи.
Посередник прибирає прямі зв’язки між окремими компонентами, змушуючи їх спілкуватися один з одним через себе.
Концептуальний приклад
Система трафіку на залізничній платформі — чудовий приклад патерну Посередник. Два потяги ніколи не конфліктують між собою за наявність вільної платформи, натомість менеджер станції stationManager
виступає посередником, який оголошує платформу вільною лише для одного потяга, а решту тримає у черзі. Коли поїзд відправляється зі станції, він сповіщає менеджера, що дає змогу прибути наступному в черзі поїзду.
train.go: Компонент
package main
type Train interface {
arrive()
depart()
permitArrival()
}
passengerTrain.go: Конкретний компонент
package main
import "fmt"
type PassengerTrain struct {
mediator Mediator
}
func (g *PassengerTrain) arrive() {
if !g.mediator.canArrive(g) {
fmt.Println("PassengerTrain: Arrival blocked, waiting")
return
}
fmt.Println("PassengerTrain: Arrived")
}
func (g *PassengerTrain) depart() {
fmt.Println("PassengerTrain: Leaving")
g.mediator.notifyAboutDeparture()
}
func (g *PassengerTrain) permitArrival() {
fmt.Println("PassengerTrain: Arrival permitted, arriving")
g.arrive()
}
freightTrain.go: Конкретний компонент
package main
import "fmt"
type FreightTrain struct {
mediator Mediator
}
func (g *FreightTrain) arrive() {
if !g.mediator.canArrive(g) {
fmt.Println("FreightTrain: Arrival blocked, waiting")
return
}
fmt.Println("FreightTrain: Arrived")
}
func (g *FreightTrain) depart() {
fmt.Println("FreightTrain: Leaving")
g.mediator.notifyAboutDeparture()
}
func (g *FreightTrain) permitArrival() {
fmt.Println("FreightTrain: Arrival permitted")
g.arrive()
}
mediator.go: Інтерфейс посередника
package main
type Mediator interface {
canArrive(Train) bool
notifyAboutDeparture()
}
stationManager.go: Конкретний посередник
package main
type StationManager struct {
isPlatformFree bool
trainQueue []Train
}
func newStationManger() *StationManager {
return &StationManager{
isPlatformFree: true,
}
}
func (s *StationManager) canArrive(t Train) bool {
if s.isPlatformFree {
s.isPlatformFree = false
return true
}
s.trainQueue = append(s.trainQueue, t)
return false
}
func (s *StationManager) notifyAboutDeparture() {
if !s.isPlatformFree {
s.isPlatformFree = true
}
if len(s.trainQueue) > 0 {
firstTrainInQueue := s.trainQueue[0]
s.trainQueue = s.trainQueue[1:]
firstTrainInQueue.permitArrival()
}
}
main.go: Клієнтський код
package main
func main() {
stationManager := newStationManger()
passengerTrain := &PassengerTrain{
mediator: stationManager,
}
freightTrain := &FreightTrain{
mediator: stationManager,
}
passengerTrain.arrive()
freightTrain.arrive()
passengerTrain.depart()
}
output.txt: Результат виконання
PassengerTrain: Arrived
FreightTrain: Arrival blocked, waiting
PassengerTrain: Leaving
FreightTrain: Arrival permitted
FreightTrain: Arrived