Design patterns
Waarnemer
Zoeken…
Opmerkingen
Wat is de bedoeling?
- Neem het principe van scheiding van zorgen aan.
- Maak een scheiding tussen het onderwerp en de waarnemer.
- Laat meerdere waarnemers reageren om een enkel onderwerp te veranderen.
Wat is de structuur?
- Onderwerp biedt een manier om te registreren, afmelden, informeren.
- Observer biedt een manier om te updaten.
Waarnemer / Java
Met het waarnemerspatroon kunnen gebruikers van een klasse zich abonneren op gebeurtenissen die plaatsvinden wanneer deze klasse gegevens enz. Verwerkt en op de hoogte worden gesteld wanneer deze gebeurtenissen plaatsvinden. In het volgende voorbeeld maken we een verwerkingsklasse en een waarnemersklasse die wordt gewaarschuwd tijdens het verwerken van een zin - als deze woorden vindt die langer zijn dan 5 letters.
De interface LongWordsObserver
definieert de waarnemer. Implementeer deze interface om een waarnemer voor evenementen te registreren.
// an observe that can be registered and receive notifications
public interface LongWordsObserver {
void notify(WordEvent event);
}
De WordEvent
klasse is de gebeurtenis die naar de waarnemersklassen wordt verzonden zodra bepaalde gebeurtenissen plaatsvinden (in dit geval werden lange woorden gevonden)
// An event class which contains the long word that was found
public class WordEvent {
private String word;
public WordEvent(String word) {
this.word = word;
}
public String getWord() {
return word;
}
}
De klasse PhraseProcessor
is de klasse die de gegeven zin verwerkt. Hiermee kunnen waarnemers worden geregistreerd met behulp van de addObserver
methode. Zodra lange woorden zijn gevonden, worden deze waarnemers opgeroepen met behulp van een instantie van de klasse WordEvent
.
import java.util.ArrayList;
import java.util.List;
public class PhraseProcessor {
// the list of observers
private List<LongWordsObserver> observers = new ArrayList<>();
// register an observer
public void addObserver(LongWordsObserver observer) {
observers.add(observer);
}
// inform all the observers that a long word was found
private void informObservers(String word) {
observers.forEach(o -> o.notify(new WordEvent(word)));
}
// the main method - process a phrase and look for long words. If such are found,
// notify all the observers
public void process(String phrase) {
for (String word : phrase.split(" ")) {
if (word.length() > 5) {
informObservers(word);
}
}
}
}
De klasse LongWordsExample
laat zien hoe u waarnemers kunt registreren, de process
kunt oproepen en meldingen kunt ontvangen wanneer lange woorden werden gevonden.
import java.util.ArrayList;
import java.util.List;
public class LongWordsExample {
public static void main(String[] args) {
// create a list of words to be filled when long words were found
List<String> longWords = new ArrayList<>();
// create the PhraseProcessor class
PhraseProcessor processor = new PhraseProcessor();
// register an observer and specify what it should do when it receives events,
// namely to append long words in the longwords list
processor.addObserver(event -> longWords.add(event.getWord()));
// call the process method
processor.process("Lorem ipsum dolor sit amet, consectetuer adipiscing elit");
// show the list of long words after the processing is done
System.out.println(String.join(", ", longWords));
// consectetuer, adipiscing
}
}
Waarnemer met IObservable en IObserver (C #)
IObserver<T>
en IObservable<T>
-interfaces kunnen worden gebruikt om een waarnemerspatroon in .NET te implementeren
-
IObservable<T>
-interface vertegenwoordigt de klasse die meldingen verzendt -
IObserver<T>
interface vertegenwoordigt de klasse die ze ontvangt
public class Stock {
private string Symbol { get; set; }
private decimal Price { get; set; }
}
public class Investor : IObserver<Stock> {
public IDisposable unsubscriber;
public virtual void Subscribe(IObservable<Stock> provider) {
if(provider != null) {
unsubscriber = provider.Subscribe(this);
}
}
public virtual void OnCompleted() {
unsubscriber.Dispose();
}
public virtual void OnError(Exception e) {
}
public virtual void OnNext(Stock stock) {
}
}
public class StockTrader : IObservable<Stock> {
public StockTrader() {
observers = new List<IObserver<Stock>>();
}
private IList<IObserver<Stock>> observers;
public IDisposable Subscribe(IObserver<Stock> observer) {
if(!observers.Contains(observer)) {
observers.Add(observer);
}
return new Unsubscriber(observers, observer);
}
public class Unsubscriber : IDisposable {
private IList<IObserver<Stock>> _observers;
private IObserver<Stock> _observer;
public Unsubscriber(IList<IObserver<Stock>> observers, IObserver<Stock> observer) {
_observers = observers;
_observer = observer;
}
public void Dispose() {
Dispose(true);
}
private bool _disposed = false;
protected virtual void Dispose(bool disposing) {
if(_disposed) {
return;
}
if(disposing) {
if(_observer != null && _observers.Contains(_observer)) {
_observers.Remove(_observer);
}
}
_disposed = true;
}
}
public void Trade(Stock stock) {
foreach(var observer in observers) {
if(stock== null) {
observer.OnError(new ArgumentNullException());
}
observer.OnNext(stock);
}
}
public void End() {
foreach(var observer in observers.ToArray()) {
observer.OnCompleted();
}
observers.Clear();
}
}
Gebruik
...
var provider = new StockTrader();
var i1 = new Investor();
i1.Subscribe(provider);
var i2 = new Investor();
i2.Subscribe(provider);
provider.Trade(new Stock());
provider.Trade(new Stock());
provider.Trade(null);
provider.End();
...
REF: Ontwerppatronen en -praktijken in .NET: het waarnemerspatroon