Mediator to behawioralny wzorzec projektowy pozwalający zredukować sprzężenie pomiędzy komponentami programu poprzez zmuszenie ich do komunikacji za pośrednictwem obiektu zwanego mediatorem.
Mediator ułatwia modyfikację, rozszerzanie i ponowne wykorzystanie komponentów gdyż z jego pomocą nie są one zależne od wielu innych klas.
Przykład koncepcyjny
Świetnym przykładem użycia wzorca Mediator jest stacja kierowania ruchem kolejowym. Dwa pociągi nie muszą się ze sobą bezpośrednio komunikować odnośnie zajętości peronu. stationManager
pełni rolę mediatora pomiędzy pociągami i pilnuje, aby tylko jeden z nich mógł wjechać na peron, zaś drugi czekał. Odjeżdżając z peronu pociąg informuje o tym fakcie stację, która z kolei udziela pozwolenia na wjazd oczekującemu pociągowi.
train.go: Komponent
package main
type Train interface {
arrive()
depart()
permitArrival()
}
passengerTrain.go: Konkretny komponent
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: Konkretny komponent
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: Interfejs mediatora
package main
type Mediator interface {
canArrive(Train) bool
notifyAboutDeparture()
}
stationManager.go: Konkretny mediator
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: Kod klienta
package main
func main() {
stationManager := newStationManger()
passengerTrain := &PassengerTrain{
mediator: stationManager,
}
freightTrain := &FreightTrain{
mediator: stationManager,
}
passengerTrain.arrive()
freightTrain.arrive()
passengerTrain.depart()
}
output.txt: Wynik działania
PassengerTrain: Arrived
FreightTrain: Arrival blocked, waiting
PassengerTrain: Leaving
FreightTrain: Arrival permitted
FreightTrain: Arrived