Observer-mønsteret i Java

1. Oversigt

I denne artikel skal vi beskrive Observer-mønsteret og se på et par Java-implementeringsalternativer.

2. Hvad er observatørmønsteret?

Observer er et adfærdsmæssigt designmønster. Det specificerer kommunikation mellem objekter: observerbar og observatører. En observerbar er et objekt, der giver besked observatører om ændringerne i dets tilstand.

For eksempel kan et nyhedsbureau underrette kanaler, når det modtager nyheder. Modtagelse af nyheder er det, der ændrer nyhedsbureauets tilstand, og det får kanalerne til at blive underrettet.

Lad os se, hvordan vi selv kan implementere det.

Lad os først definere Nyhedsbureau klasse:

offentlig klasse NewsAgency {private strengnyheder; private List-kanaler = ny ArrayList (); public void addObserver (Channel channel) {this.channels.add (channel); } public void removeObserver (Channel channel) {this.channels.remove (channel); } public void setNews (String news) {this.news = news; for (Channel channel: this.channels) {channel.update (this.news); }}}

Nyhedsbureau er en observerbar, og hvornår nyheder bliver opdateret, tilstanden af Nyhedsbureau ændringer. Når ændringen sker, Nyhedsbureau underretter observatørerne om dette ved at ringe til deres opdater () metode.

For at være i stand til det skal det observerbare objekt beholde referencer til observatørerne, og i vores tilfælde er det kanaler variabel.

Lad os nu se, hvordan observatøren, det Kanal klasse, kan se ud. Det skal have opdater () metode, der påberåbes, når staten Nyhedsbureau ændringer:

offentlig klasse NewsChannel implementerer Channel {private String news; @Override offentlig ugyldig opdatering (Objektnyheder) {this.setNews ((String) nyheder); }}

Det Kanal interface har kun en metode:

offentlig grænseflade Kanal {offentlig ugyldig opdatering (objekt o); }

Nu, hvis vi tilføjer en forekomst af NewsChannel til listen over observatører, og ændre tilstanden af Nyhedsbureau, forekomsten af NewsChannel vil blive opdateret:

NewsAgency observerbar = ny NewsAgency (); NewsChannel observatør = ny NewsChannel (); observerbar.addObserver (observatør); observerbar.setNews ("nyheder"); assertEquals (observer.getNews (), "nyheder");

Der er en foruddefineret Observer interface i Java-kernebiblioteker, hvilket gør implementeringen af ​​observatørmønstret endnu enklere. Lad os se på det.

3. Implementering med Observer

Det java.util.Observer interface definerer opdater () metode, så der er ingen grund til at definere det selv som vi gjorde i det foregående afsnit.

Lad os se, hvordan vi kan bruge det i vores implementering:

offentlig klasse ONewsChannel implementerer Observer {private String-nyheder; @Override offentlig ugyldig opdatering (Observable o, Object news) {this.setNews ((String) news); }} 

Her kommer det andet argument fra Observerbar som vi vil se nedenfor.

At definere det observerbare, vi har brug for at udvide Java'er Observerbar klasse:

offentlig klasse ONewsAgency udvider Observable {private String news; public void setNews (String news) {this.news = news; setChanged (); notifyObservers (nyheder); }}

Bemærk, at vi ikke behøver at ringe til observatørens opdater () metode direkte. Vi ringer bare setChanged () og notifyObservers (), og Observerbar klassen gør resten for os.

Den indeholder også en liste over observatører og udsætter metoder til at opretholde denne liste - addObserver () og deleteObserver ().

For at teste resultatet er vi bare nødt til at tilføje observatøren til denne liste og indstille nyhederne:

ONewsAgency observerbar = ny ONewsAgency (); ONewsChannel observatør = ny ONewsChannel (); observerbar.addObserver (observatør); observerbar.setNews ("nyheder"); assertEquals (observer.getNews (), "nyheder");

Observer interface er ikke perfekt og er udfaset siden Java 9. En af dens ulemper er det Observerbar er ikke en grænseflade men en klasse, det er derfor, underklasser ikke kan bruges som observerbare.

En udvikler kunne også tilsidesætte nogle af Observerbar'S synkroniserede metoder og forstyrrer deres trådsikkerhed.

Lad os se på ProperyChangeListener interface, som anbefales i stedet for at bruge Observer.

4. Implementering med PropertyChangeListener

I denne implementering skal en observerbar holde en henvisning til PropertyChangeSupport eksempel. Det hjælper med at sende underretningerne til observatører, når en egenskab i klassen ændres.

Lad os definere det observerbare:

offentlig klasse PCLNewsAgency {private String-nyheder; privat PropertyChangeSupport support; offentlig PCLNewsAgency () {support = ny PropertyChangeSupport (dette); } public void addPropertyChangeListener (PropertyChangeListener pcl) {support.addPropertyChangeListener (pcl); } offentlig tomrum removePropertyChangeListener (PropertyChangeListener pcl) {support.removePropertyChangeListener (pcl); } public void setNews (String value) {support.firePropertyChange ("news", this.news, value); this.news = værdi; }}

Brug af dette support, vi kan tilføje og fjerne observatører og underrette dem, når tilstanden for de observerbare ændringer ændres:

support.firePropertyChange ("nyheder", dette. nyheder, værdi);

Her er det første argument navnet på den observerede ejendom. Det andet og tredje argument er dets gamle og nye værdi i overensstemmelse hermed.

Observatører bør implementere PropertyChangeListener:

offentlig klasse PCLNewsChannel implementerer PropertyChangeListener {private strengnyheder; public void propertyChange (PropertyChangeEvent evt) {this.setNews ((String) evt.getNewValue ()); }}

På grund af den PropertyChangeSupport klasse, der laver ledningerne for os, kan vi gendanne den nye ejendomsværdi fra begivenheden.

Lad os teste implementeringen for at sikre, at den også fungerer:

PCLNewsAgency observerbar = ny PCLNewsAgency (); PCLNewsChannel observatør = ny PCLNewsChannel (); observerbar.addPropertyChangeListener (observatør); observerbar.setNews ("nyheder"); assertEquals (observer.getNews (), "nyheder");

5. Konklusion

I denne artikel har vi undersøgt to måder at implementere Observer design mønster i Java, med PropertyChangeListener tilgang foretrækkes.

Kildekoden til artiklen er tilgængelig på GitHub.