Het waarnemerspatroon in Java

1. Overzicht

In dit artikel gaan we het Observer-patroon beschrijven en een paar Java-implementatie-alternatieven bekijken.

2. Wat is het waarnemerspatroon?

Observer is een gedragsontwerppatroon. Het specificeert communicatie tussen objecten: waarneembaar en waarnemers. Een waarneembaar is een object dat waarschuwt waarnemers over de veranderingen in zijn toestand.

Een persbureau kan bijvoorbeeld kanalen op de hoogte stellen wanneer het nieuws ontvangt. Het ontvangen van nieuws is wat de toestand van het persbureau verandert, en het zorgt ervoor dat de kanalen op de hoogte worden gebracht.

Laten we eens kijken hoe we het zelf kunnen implementeren.

Laten we eerst de Nieuws Agentschap klasse:

openbare klasse NewsAgency {privé String-nieuws; privélijstkanalen = nieuwe ArrayList (); public void addObserver (kanaalkanaal) {this.channels.add (kanaal); } public void removeObserver (kanaalkanaal) {this.channels.remove (kanaal); } public void setNews (String nieuws) {this.news = nieuws; voor (Channel channel: this.channels) {channel.update (this.news); }}}

Nieuws Agentschap is een waarneembare, en wanneer nieuws wordt bijgewerkt, de staat van Nieuws Agentschap veranderingen. Als de verandering plaatsvindt, Nieuws Agentschap informeert de waarnemers over dit feit door hun bijwerken() methode.

Om dat te kunnen doen, moet het waarneembare object verwijzingen naar de waarnemers behouden, en in ons geval is het de kanalen variabele.

Laten we nu eens kijken hoe de waarnemer, de Kanaal klasse, kan eruit zien. Het zou de bijwerken() methode die wordt aangeroepen wanneer de staat van Nieuws Agentschap veranderingen:

public class NewsChannel implementeert Channel {private String news; @Override public void update (Object news) {this.setNews ((String) news); }}

De Kanaal interface heeft maar één methode:

openbare interface Kanaal {openbare ongeldige update (Object o); }

Als we nu een instantie van Nieuwszender naar de lijst van waarnemers, en verander de status van Nieuws Agentschap, de instantie van Nieuwszender zal geüpdatet worden:

NewsAgency observable = nieuwe NewsAgency (); NewsChannel waarnemer = nieuw NewsChannel (); observable.addObserver (waarnemer); observable.setNews ("nieuws"); assertEquals (observer.getNews (), "nieuws");

Er is een voorgedefinieerd Waarnemer interface in Java-kernbibliotheken, waardoor het implementeren van het waarnemerspatroon nog eenvoudiger wordt. Laten we ernaar kijken.

3. Implementatie met Waarnemer

De java.util.Observer interface definieert de bijwerken() methode, dus het is niet nodig om het zelf te definiëren zoals we in de vorige sectie hebben gedaan.

Laten we eens kijken hoe we het kunnen gebruiken in onze implementatie:

openbare klasse ONewsChannel implementeert Observer {private String news; @Override public void update (Observable o, Object news) {this.setNews ((String) news); }} 

Hier komt het tweede argument vandaan Waarneembaar zoals we hieronder zullen zien.

Om het waarneembare te definiëren, we moeten Java's uitbreiden Waarneembaar klasse:

public class ONewsAgency breidt Observable {private String news; public void setNews (String nieuws) {this.news = nieuws; setChanged (); meldObservers (nieuws); }}

Merk op dat we de waarnemer niet hoeven te bellen bijwerken() methode rechtstreeks. We bellen gewoon setChanged () en meldenObservers (), en de Waarneembaar de klas doet de rest voor ons.

Het bevat ook een lijst met waarnemers en legt methoden bloot om die lijst bij te houden - addObserver () en deleteObserver ().

Om het resultaat te testen, hoeven we alleen maar de waarnemer aan deze lijst toe te voegen en het nieuws in te stellen:

ONewsAgency observable = nieuwe ONewsAgency (); ONewsChannel waarnemer = nieuw ONewsChannel (); observable.addObserver (waarnemer); observable.setNews ("nieuws"); assertEquals (observer.getNews (), "nieuws");

Waarnemer interface is niet perfect en is verouderd sinds Java 9. Een van de nadelen is dat Waarneembaar is geen interface maar een klasse, daarom kunnen subklassen niet als observabelen worden gebruikt.

Ook kan een ontwikkelaar enkele van de Waarneembaar‘S gesynchroniseerde methoden en verstoren hun thread-veiligheid.

Laten we eens kijken naar de ProperyChangeListener interface, die wordt aanbevolen in plaats van Waarnemer.

4. Implementatie met PropertyChangeListener

In deze implementatie moet een waarneembare een verwijzing naar de PropertyChangeSupport voorbeeld. Het helpt om de notificaties naar waarnemers te sturen wanneer een eigenschap van de klasse wordt gewijzigd.

Laten we het waarneembare definiëren:

openbare klasse PCLNewsAgency {privé String-nieuws; private PropertyChangeSupport ondersteuning; openbare PCLNewsAgency () {support = nieuwe PropertyChangeSupport (dit); } openbare ongeldige addPropertyChangeListener (PropertyChangeListener pcl) {support.addPropertyChangeListener (pcl); } openbare ongeldige removePropertyChangeListener (PropertyChangeListener pcl) {support.removePropertyChangeListener (pcl); } public void setNews (String-waarde) {support.firePropertyChange ("nieuws", this.news, waarde); this.news = waarde; }}

Dit gebruiken ondersteuningkunnen we waarnemers toevoegen en verwijderen, en hen op de hoogte stellen wanneer de toestand van de waarneembare veranderingen:

support.firePropertyChange ("nieuws", this.news, waarde);

Hier is het eerste argument de naam van de waargenomen eigenschap. Het tweede en derde argument zijn dienovereenkomstig de oude en nieuwe waarde.

Waarnemers moeten implementeren PropertyChangeListener:

openbare klasse PCLNewsChannel implementeert PropertyChangeListener {privé String-nieuws; openbare ongeldige propertyChange (PropertyChangeEvent evt) {this.setNews ((String) evt.getNewValue ()); }}

Vanwege de PropertyChangeSupport class die de bedrading voor ons doet, kunnen we de nieuwe eigendomswaarde van het evenement herstellen.

Laten we de implementatie testen om er zeker van te zijn dat deze ook werkt:

PCLNewsAgency observable = nieuwe PCLNewsAgency (); PCLNewsChannel-waarnemer = nieuwe PCLNewsChannel (); observable.addPropertyChangeListener (waarnemer); observable.setNews ("nieuws"); assertEquals (observer.getNews (), "nieuws");

5. Conclusie

In dit artikel hebben we twee manieren onderzocht om het Waarnemer ontwerppatroon in Java, met de PropertyChangeListener benadering heeft de voorkeur.

De broncode voor het artikel is beschikbaar op GitHub.