“Патерн Вівторка” #23: Медіатор (Mediator)
|Вже трохи часу пройшло від коли я написав попередній “патерн вівторка”. Чесно кажучи не знаю що було справжньою причиною цієї задержки.
Я трохи думав над тим який має бути приклад для Медіатора і мені на думку нічого кращого ніж класичний приклад із UI не спадало. Потім ще пару варіантів аж поки не спало на думку взаємодія нейронів. Я ще трохи подумав і в голову прийшла геніальна ідея (звичайно я не ручаюся, що більше такого прикладу немає, але я його придумав сам). Наш мозок є медіатором для різних частин тіла. Мозок ідеально підходить під опис дизайн патерну медіатор.
Просто спробуйте уявити, якби кожна із частин вашого тіла знала одна про іншу. Якщо б ваше око бачило щось приємне, то воно мало б знати як напряму зв’язатися із ногами і змусити їх рухатися у заданому напрямку. Або якщо б вас хтось вдарив в живіт, ваш живіт б мусів навчитися захищатися руками. Живіт може й боліти, тоді він буде мусіти знати про цілу систему м’язів, щоб змусити тіло прийняти лежаче положення. І взагалі для будь-чого, що приймає інформація і опісля якісь дії мають бути прийняті. Взаємодія описана вище, як багато-до-багатьох не є природньою для нашого тіла. Проте, чомусь, вона часто застосовна деякими програмістами до їхнього коду. Спочатку, поки програміст все пише по свіжому, такий код працює нормально, але із часом він перетворється на суцільний спагетті безлад в якому розібратися важко і змінити поведінку, не поломавши чогось тоже складно.
Наше тіло має одну центральну систему, яка аналізує прийняті сигнали і здійснює потрібні реакції. Це можна застосувати і до коду, який ми пишемо.
МЕДІТОР
Медіатор – це дизнай патрен який централізує взаємодію між компонентами таким чином послаблюючи їхню зв’язаність.
Медіатор елегантно спрощує розуміння взаємодій між компонентами. Це полегшує підтримку коду у майбутньому, але, оскільки логіка централізована, може стати досить складним, зрештою чим наш мозок і є.
Як видно мозок знає як діяти в різних ситуаціях і які частини тіла слід задіяти. То як це відбувається?
Мозок (Mediator) знає про кожну частину тіла (Colleague), а кожна частина тіла знає про свій мозок, тому може передавати сигнали йому та приймати їх. Звичайно кожна частина тіла виконує ще й свою безпосередню функціональність.
Базовий клас Colleague (знає про мозок)
// Colleague
class BodyPart
{
private readonly Brain _brain;
public BodyPart(Brain brain)
{
_brain = brain;
}
public void Changed()
{
_brain.SomethingHappenedToBodyPart(this);
}
}
Конкретна реазізація Colleague може вигладати так:
class Ear : BodyPart
{
private string _sounds = string.Empty;
public Ear(Brain brain)
: base(brain)
{
}
public void HearSomething()
{
Console.WriteLine("Enter what you hear:");
_sounds = Console.ReadLine();
Changed();
}
public string GetSounds()
{
return _sounds;
}
}
Як бачимо вухо (Ear) може чути (HearSomething) і може видати звуки на аналіз мозку (GetSounds). Деякі чатини тіла мають іншу функціональність. Як для прикладу реалізація класу обличчя (Face):
class Face : BodyPart
{
public Face(Brain brain)
: base(brain)
{
}
public void Smile()
{
Console.WriteLine("FACE: Smiling...");
}
}
Медіатор або Мозок (Brain)
Як і слід було оцікувати клас медіатор є досить громіздким оскільки він відповідає за “розрулювання” ситуації. Можливо вам не сподобається так як реалізовано цей конкретний мозок, але це не є аж на стільки важливо. Важливо зрозуміти як воно діє.
// Mediator
class Brain
{
public Brain()
{
CreateBodyParts();
}
private void CreateBodyParts()
{
Ear = new Ear(this);
Eye = new Eye(this);
Face = new Face(this);
Hand = new Hand(this);
Leg = new Leg(this);
}
public Ear Ear { get; private set; }
public Eye Eye { get; private set; }
public Face Face { get; private set; }
public Hand Hand { get; private set; }
public Leg Leg { get; private set; }
public void SomethingHappenedToBodyPart(BodyPart bodyPart)
{
if (bodyPart is Ear)
{
string heardSounds = ((Ear)bodyPart).GetSounds();
if (heardSounds.Contains("stupid"))
{
// attacking offender
Leg.StepForward();
Hand.HitPersonNearYou();
Leg.Kick();
}
else if (heardSounds.Contains("cool"))
{
Face.Smile();
}
}
else if (bodyPart is Eye)
{
// brain can analyze what you see and
// can react appropriately using different body parts
}
else if (bodyPart is Hand)
{
var hand = (Hand)bodyPart;
bool hurtingFeeling = hand.DoesItHurt();
if (hurtingFeeling)
{
Leg.StepBack();
}
bool itIsNice = hand.IsItNice();
if (itIsNice)
{
Leg.StepForward();
Hand.Embrace();
}
}
else if (bodyPart is Leg)
{
// leg can also feel something if you would like it to
}
}
}
Чесно кажучи мені самому сподобався цей приклад.
UML
Як уже запитували багато раз я додаю трохи UML. Клікайте на картинку, щоб придивитися до деталей.