Het mediatorpatroon in Java

1. Overzicht

In dit artikel zullen we het bekijken het Mediator Pattern, een van de GoF-gedragspatronen. We zullen het doel ervan beschrijven en uitleggen wanneer we het moeten gebruiken.

Zoals gewoonlijk zullen we ook een eenvoudig codevoorbeeld geven.

2. Bemiddelaarspatroon

Bij objectgeoriënteerd programmeren moeten we dat altijd proberen ontwerp het systeem zo dat componenten losjes gekoppeld en herbruikbaar zijn. Door deze aanpak is onze code gemakkelijker te onderhouden en te testen.

In het echte leven hebben we echter vaak te maken met een complexe reeks afhankelijke objecten. Dit is wanneer het Mediator-patroon van pas kan komen.

De bedoeling van het mediatorpatroon is om de complexiteit en afhankelijkheden tussen nauw gekoppelde objecten die rechtstreeks met elkaar communiceren te verminderen. Dit wordt bereikt door een mediator-object te maken dat zorgt voor de interactie tussen afhankelijke objecten. Alle communicatie verloopt dus via de mediator.

Dit bevordert een losse koppeling, omdat een reeks samenwerkende componenten niet langer rechtstreeks hoeft te interageren. In plaats daarvan verwijzen ze alleen naar het object met één bemiddelaar. Op deze manier is het ook gemakkelijker om deze objecten opnieuw te gebruiken in andere delen van het systeem.

3. Het UML-diagram van Mediator Pattern

Laten we het patroon nu visueel bekijken:

In het bovenstaande UML-diagram kunnen we de volgende deelnemers identificeren:

  • Bemiddelaar definieert de interface de Collega objecten gebruiken om te communiceren
  • Collega definieert de abstracte klasse met een enkele verwijzing naar de Bemiddelaar
  • ConcreteMediator vat de interactielogica tussen Collega voorwerpen
  • BetonCollega 1 en ConcreteColleague 2 communiceer alleen via de Bemiddelaar

Zoals we kunnen zien, Collega objecten verwijzen niet rechtstreeks naar elkaar. In plaats daarvan wordt alle communicatie uitgevoerd door de Bemiddelaar.

Bijgevolg, BetonCollega 1 en ConcreteColleague 2 kan gemakkelijker worden hergebruikt.

Ook voor het geval we de weg moeten veranderen Collega objecten samenwerken, hoeven we alleen de ConcreteMediator logica. Of we kunnen een nieuwe implementatie van het Bemiddelaar.

4. Java-implementatie

Nu we een duidelijk idee hebben van de theorie, gaan we naar een voorbeeld kijken om het concept in de praktijk beter te begrijpen.

4.1. Voorbeeldscenario

Stel je voor dat we een eenvoudig koelsysteem bouwen dat bestaat uit een ventilator, een voeding en een knop. Door op de knop te drukken, wordt de ventilator in- of uitgeschakeld. Voordat we de ventilator aanzetten, moeten we de stroom aanzetten. Evenzo moeten we de stroom uitschakelen direct nadat de ventilator is uitgeschakeld.

Laten we nu eens kijken naar de voorbeeldimplementatie:

openbare klasse Knop {privé Fan-fan; // constructor, getters en setters public void press () {if (fan.isOn ()) {fan.turnOff (); } anders {fan.turnOn (); }}}
openbare klasse Fan {privéknopknop; particuliere PowerSupplier powerSupplier; private boolean isOn = false; // constructor, getters en setters public void turnOn () {powerSupplier.turnOn (); isOn = waar; } public void turnOff () {isOn = false; powerSupplier.turnOff (); }}
public class PowerSupplier {public void turnOn () {// implementatie} public void turnOff () {// implementatie}}

Laten we vervolgens de functionaliteit testen:

@Test openbare leegte gegevenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff () {assertFalse (fan.isOn ()); knop. druk op (); assertTrue (fan.isOn ()); knop. druk op (); assertFalse (fan.isOn ()); }

Alles lijkt goed te werken. Maar merk op hoe Knop, ventilator, en Energie leverancier klassen zijn nauw met elkaar verbonden. De Knop werkt rechtstreeks op de Ventilator en de Ventilator interageert met beide Knop en Energie leverancier.

Het zou moeilijk zijn om het Knop klasse in andere modules. Als we een tweede voeding aan ons systeem moeten toevoegen, moeten we ook het Ventilator class 'logica.

4.2. Het bemiddelingspatroon toevoegen

Laten we nu het Mediator-patroon implementeren om de afhankelijkheden tussen onze klassen te verminderen en de code beter herbruikbaar te maken.

Laten we eerst het Bemiddelaar klasse:

openbare klasse Bemiddelaar {privéknopknop; privé Fan fan; particuliere PowerSupplier powerSupplier; // constructor, getters en setters public void press () {if (fan.isOn ()) {fan.turnOff (); } anders {fan.turnOn (); }} public void start () {powerSupplier.turnOn (); } public void stop () {powerSupplier.turnOff (); }}

Laten we vervolgens de resterende klassen aanpassen:

openbare klasse Button {privé bemiddelaar bemiddelaar; // constructor, getters en setters public void press () {mediator.press (); }}
openbare klasse Fan {privé bemiddelaar bemiddelaar; private boolean isOn = false; // constructor, getters en setters public void turnOn () {mediator.start (); isOn = waar; } public void turnOff () {isOn = false; mediator.stop (); }}

Nogmaals, laten we de functionaliteit testen:

@Test openbare leegte gegevenTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff () {assertFalse (fan.isOn ()); knop. druk op (); assertTrue (fan.isOn ()); knop. druk op (); assertFalse (fan.isOn ()); }

Ons koelsysteem werkt zoals verwacht.

Nu we het Mediator-patroon hebben geïmplementeerd, is geen van de Knop, Ventilator, of Energie leverancier klassen communiceren rechtstreeks. Ze hebben slechts één enkele verwijzing naar de Bemiddelaar.

Als we in de toekomst een tweede voeding moeten toevoegen, hoeven we alleen maar te updaten Bemiddelaar logica; Knop en Ventilator klassen blijven onaangeroerd.

Dit voorbeeld laat zien hoe gemakkelijk we afhankelijke objecten kunnen scheiden en ons systeem gemakkelijker te onderhouden maken.

5. Wanneer moet u het bemiddelingspatroon gebruiken?

Het Mediator-patroon is een goede keuze als we te maken hebben met een reeks objecten die nauw met elkaar zijn gekoppeld en moeilijk te onderhouden zijn. Op deze manier kunnen we de afhankelijkheden tussen objecten verminderen en de algehele complexiteit verminderen.

Bovendien extraheren we door het mediator-object te gebruiken de communicatielogica naar de enkele component, daarom volgen we het Single Responsibility Principle. Bovendien kunnen we nieuwe bemiddelaars introduceren zonder de resterende delen van het systeem te hoeven wijzigen. Daarom volgen we het open-gesloten principe.

Soms kunnen we echter te veel nauw gekoppelde objecten hebben vanwege het gebrekkige ontwerp van het systeem. Als dit het geval is, moeten we het Mediator-patroon niet toepassen. In plaats daarvan moeten we een stap terug doen en opnieuw nadenken over de manier waarop we onze lessen hebben gemodelleerd.

Zoals bij alle andere patronen, we moeten onze specifieke use case in overweging nemen voordat we blindelings het Mediator Pattern implementeren.

6. Conclusie

In dit artikel leerden we over het bemiddelaarspatroon. We hebben uitgelegd welk probleem dit patroon oplost en wanneer we het daadwerkelijk zouden moeten overwegen. We hebben ook een eenvoudig voorbeeld van het ontwerppatroon geïmplementeerd.

Zoals altijd zijn de volledige codevoorbeelden beschikbaar op GitHub.


$config[zx-auto] not found$config[zx-overlay] not found