Посредник (Mediator)
Паттерн Mediator относится к поведенческим паттернам уровня объекта.
Паттерн Mediator предоставляет объект-посредник, скрывающий способ взаимодействия множества других объектов-коллег. Mediator делает систему слабо связанной, избавляя объекты от необходимости ссылаться друг на друга, что позволяет изменять взаимодействие между ними независимо.
Например, у нас есть посредник между заводом производства хлебобулочных изделий, фермером и магазином сбыта. Посредник избавляет фермера от взаимодействия с заводом, который использует его сырье, а завод от взаимодействия с магазином, в который поступает продукция для сбыта.
Требуется для реализации:
- Интерфейс Mediator - посредник описывающий организацию процесса по обмену информацией между объектами типа Colleague;
- Класс ConcreteMediator, реализующий интерфейс Mediator;
- Базовый абстрактный класс Colleague - коллега описывающий организацию процесса взаимодействия объектов-коллег с объектом типа Mediator;
- Класс ConcreteColleague, реализующий интерфейс Colleague. Каждый объект-коллега знает только об объекте-медиаторе. Все объекты-коллеги обмениваются информацией только через посредника.
[!] В описании паттерна применяются общие понятия, такие как Класс, Объект, Абстрактный класс. Применимо к языку Go, это Пользовательский Тип, Значение этого Типа и Интерфейс. Также в языке Go за место общепринятого наследования используется агрегирование и встраивание.
//mediator.go
// Package mediator is an example of the Mediator Pattern.
package mediator
// Mediator provides a mediator interface.
type Mediator interface {
Notify(msg string)
}
// Тип ConcreteMediator, реализует посредника
type ConcreteMediator struct {
*Farmer
*Cannery
*Shop
}
// Notify implementation.
func (m *ConcreteMediator) Notify(msg string) {
if msg == "Farmer: Tomato complete..." {
m.Cannery.AddMoney(-15000.00)
m.Farmer.AddMoney(15000.00)
m.Cannery.MakeKetchup(m.Farmer.GetTomato())
} else if msg == "Cannery: Ketchup complete..." {
m.Shop.AddMoney(-30000.00)
m.Cannery.AddMoney(30000.00)
m.Shop.SellKetchup(m.Cannery.GetKetchup())
}
}
// СonnectСolleagues connects all colleagues.
func СonnectСolleagues(farmer *Farmer, cannery *Cannery, shop *Shop) {
mediator := &ConcreteMediator{
Farmer: farmer,
Cannery: cannery,
Shop: shop,
}
mediator.Farmer.SetMediator(mediator)
mediator.Cannery.SetMediator(mediator)
mediator.Shop.SetMediator(mediator)
}
// Farmer implements a Farmer colleague
type Farmer struct {
mediator Mediator
tomato int
money float64
}
// SetMediator sets mediator.
func (f *Farmer) SetMediator(mediator Mediator) {
f.mediator = mediator
}
// AddMoney adds money.
func (f *Farmer) AddMoney(m float64) {
f.money += m
}
// GrowTomato implementation.
func (f *Farmer) GrowTomato(tomato int) {
f.tomato = tomato
f.money -= 7500.00
f.mediator.Notify("Farmer: Tomato complete...")
}
// GetTomato returns tomatos.
func (f *Farmer) GetTomato() int {
return f.tomato
}
// Cannery implements a Cannery colleague.
type Cannery struct {
mediator Mediator
ketchup int
money float64
}
// SetMediator sets mediator.
func (c *Cannery) SetMediator(mediator Mediator) {
c.mediator = mediator
}
// AddMoney adds money.
func (c *Cannery) AddMoney(m float64) {
c.money += m
}
// MakeKetchup implementation.
func (c *Cannery) MakeKetchup(tomato int) {
c.ketchup = tomato
c.mediator.Notify("Cannery: Ketchup complete...")
}
// GetKetchup returns ketchup.
func (c *Cannery) GetKetchup() int {
return c.ketchup
}
// Shop implements a Shop colleague.
type Shop struct {
mediator Mediator
money float64
}
// SetMediator sets mediator.
func (s *Shop) SetMediator(mediator Mediator) {
s.mediator = mediator
}
// AddMoney adds money.
func (s *Shop) AddMoney(m float64) {
s.money += m
}
// SellKetchup converts ketchup to money.
func (s *Shop) SellKetchup(ketchup int) {
s.money = float64(ketchup) * 54.75
}
// GetMoney returns money.
func (s *Shop) GetMoney() float64 {
return s.money
}
//mediator_test.go
package mediator
import (
"testing"
)
func TestMediator(t *testing.T) {
farmer := new(Farmer)
cannery := new(Cannery)
shop := new(Shop)
farmer.AddMoney(7500.00)
cannery.AddMoney(15000.00)
shop.AddMoney(30000.00)
СonnectСolleagues(farmer, cannery, shop)
// A farmer grows a 1000kg tomato
// and informs the mediator about the completion of his work.
// Next, the mediator sends the tomatoes to the cannery.
// After the cannery produces 1000 packs of ketchup,
// he informs the mediator about his delivery to the store.
farmer.GrowTomato(1000)
expect := float64(54750)
result := shop.GetMoney()
if result != expect {
t.Errorf("Expect result to equal %f, but %f.\n", expect, result)
}
}