Mediatormønsteret i Java

1. Oversikt

I denne artikkelen vil vi se på mediatormønsteret, et av GoFs atferdsmønstre. Vi beskriver formålet og forklarer når vi skal bruke det.

Som vanlig vil vi også gi et enkelt kodeeksempel.

2. Meglermønster

I objektorientert programmering skal vi alltid prøve å utform systemet på en slik måte at komponentene er løst koblet og gjenbrukbare. Denne tilnærmingen gjør koden vår lettere å vedlikeholde og teste.

I det virkelige liv trenger vi imidlertid ofte å håndtere et komplekst sett av avhengige objekter. Dette er når Mediator-mønsteret kan være nyttig.

Hensikten med Mediator-mønsteret er å redusere kompleksiteten og avhengigheten mellom tett sammenkoblede objekter som kommuniserer direkte med hverandre. Dette oppnås ved å lage et mediatorobjekt som tar seg av samspillet mellom avhengige objekter. Derfor går all kommunikasjon gjennom megleren.

Dette fremmer løs kobling, ettersom et sett med komponenter som jobber sammen ikke lenger trenger å samhandle direkte. I stedet refererer de bare til enkeltformidlerobjektet. På denne måten er det også lettere å gjenbruke disse objektene i andre deler av systemet.

3. Mediatormønsterets UML-diagram

La oss nå se på mønsteret visuelt:

I UML-diagrammet ovenfor kan vi identifisere følgende deltakere:

  • Megler definerer grensesnittet Kollega objekter bruker for å kommunisere
  • Kollega definerer den abstrakte klassen som holder en enkelt referanse til Megler
  • ConcreteMediator innkapsler samspillslogikken mellom Kollega gjenstander
  • BetongKollega1 og BetongColleague2 bare kommunisere gjennom Megler

Som vi kan se, Kollega objekter refererer ikke til hverandre direkte. I stedet blir all kommunikasjon utført av Megler.

Følgelig BetongKollega1 og BetongColleague2 kan lettere brukes på nytt.

I tilfelle vi trenger å endre måten Kollega gjenstander fungerer sammen, trenger vi bare å endre ConcreteMediator logikk. Eller vi kan lage en ny implementering av Megler.

4. Java-implementering

Nå som vi har en klar ide om teorien, la oss se på et eksempel for bedre å forstå konseptet i praksis.

4.1. Eksempel på scenario

Tenk deg at vi bygger et enkelt kjølesystem som består av en vifte, en strømforsyning og en knapp. Trykk på knappen for å slå på eller av viften. Før vi slår på viften, må vi slå på strømmen. På samme måte må vi slå av strømmen rett etter at viften er slått av.

La oss nå se på implementeringen av eksemplet:

offentlig klasse Knapp {privat Fan fan; // constructor, getters and setters public void press () {if (fan.isOn ()) {fan.turnOff (); } annet {fan.turnOn (); }}}
offentlig klasse vifte {privat knapp-knapp; private PowerSupplier powerSupplier; privat boolsk isOn = false; // constructor, getters and setters public void turnOn () {powerSupplier.turnOn (); isOn = sant; } offentlig ugyldig turnOff () {isOn = false; powerSupplier.turnOff (); }}
offentlig klasse PowerSupplier {offentlig ugyldig turnOn () {// implementering} offentlig ugyldig slå av () {// implementering}}

La oss deretter teste funksjonaliteten:

@Test offentlig ugyldighet gittTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff () {assertFalse (fan.isOn ()); knapp. trykk (); assertTrue (fan.isOn ()); knapp. trykk (); assertFalse (fan.isOn ()); }

Alt ser ut til å fungere bra. Men legg merke til hvordan Knapp, vifte, og Strømforsyning klassene er tett sammenkoblet. De Knapp opererer direkte på Fan og Fan samhandler med begge Knapp og Strømforsyning.

Det ville være vanskelig å gjenbruke Knapp klasse i andre moduler. Også, hvis vi trenger å legge til en ekstra strømforsyning i systemet vårt, må vi endre Fan klassens logikk.

4.2. Legge til meglermønsteret

La oss nå implementere Mediator-mønsteret for å redusere avhengigheten mellom klassene våre og gjøre koden mer gjenbrukbar.

La oss først introdusere Megler klasse:

offentlig klasse mekler {privat knapp-knapp; privat Fan fan; private PowerSupplier powerSupplier; // constructor, getters and setters public void press () {if (fan.isOn ()) {fan.turnOff (); } annet {fan.turnOn (); }} offentlig ugyldig start () {powerSupplier.turnOn (); } offentlig ugyldig stopp () {powerSupplier.turnOff (); }}

La oss deretter endre de gjenværende klassene:

offentlig klasse Knapp {privat megler megler; // constructor, getters and setters public void press () {mediator.press (); }}
offentlig klasse Fan {privat mekler megler; privat boolsk isOn = false; // constructor, getters and setters public void turnOn () {mediator.start (); isOn = sant; } offentlig ugyldig turnOff () {isOn = false; mediator.stop (); }}

Igjen, la oss teste funksjonaliteten:

@Test offentlig ugyldighet gittTurnedOffFan_whenPressingButtonTwice_fanShouldTurnOnAndOff () {assertFalse (fan.isOn ()); knapp. trykk (); assertTrue (fan.isOn ()); knapp. trykk (); assertFalse (fan.isOn ()); }

Kjølesystemet vårt fungerer som forventet.

Nå som vi har implementert Mediator-mønsteret, er det ingen av Knapp, Fan, eller Strømforsyning klassene kommuniserer direkte. De har bare en enkelt referanse til Megler.

Hvis vi trenger å legge til en ekstra strømforsyning i fremtiden, er alt vi trenger å gjøre å oppdatere Megler logikk; Knapp og Fan klassene forblir uberørt.

Dette eksemplet viser hvor enkelt vi kan skille avhengige objekter og gjøre systemet vårt lettere å vedlikeholde.

5. Når skal du bruke meglermønsteret

Mediatormønsteret er et godt valg hvis vi må takle et sett med gjenstander som er tett sammenkoblet og vanskelig å vedlikeholde. På denne måten kan vi redusere avhengigheten mellom objekter og redusere den totale kompleksiteten.

I tillegg, ved å bruke mediatorobjektet, trekker vi ut kommunikasjonslogikken til den enkelte komponenten, derfor følger vi prinsippet om enkelt ansvar. Videre kan vi introdusere nye meglere uten behov for å endre de gjenværende delene av systemet. Derfor følger vi det åpne-lukkede prinsippet.

Noen ganger kan vi imidlertid ha for mange tett sammenkoblede gjenstander på grunn av feil på utformingen av systemet. Hvis dette er tilfelle, bør vi ikke bruke Mediator-mønsteret. I stedet bør vi ta et skritt tilbake og tenke over måten vi har modellert klassene våre på.

Som med alle andre mønstre, Vi må vurdere vår spesifikke brukssak før vi blindt implementerer Mediator-mønsteret.

6. Konklusjon

I denne artikkelen fikk vi vite om formidlermønsteret. Vi forklarte hvilket problem dette mønsteret løser, og når vi faktisk bør vurdere å bruke det. Vi implementerte også et enkelt eksempel på designmønsteret.

Som alltid er de komplette kodeeksemplene tilgjengelig på GitHub.


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