Megfigyelő programtervezési minta

Az Observer, vagy Megfigyelő minta egy olyan szoftvertervezési minta, melyben egy objektum, melyet alanynak hívunk, listát vezet alárendeltjeiről, akiket megfigyelőknek hívunk és automatikusan értesíti őket bármilyen állapotváltozásról, többnyire valamely metódusuk meghívásán keresztül. Többnyire elosztott eseménykezelő rendszerek kialakításakor használjuk. A Megfigyelő minta kulcsfontosságú része az ismert Model-View-Controller (MVC, Modell-Nézet-Vezérlő) architekturális modellnek. A Megfigyelő mintát számos programozási könyvtár és rendszer alkalmazza, többek között szinte minden GUI toolkit.

A Megfigyelő minta memóriaszivárgást okozhat, melyet elévülő hallgató problémaként is ismerhetünk, mivel az alap implementáció során explicit regisztrációt és explicit deregisztrációt is végrehajtunk, mint a megsemmisítési mintában, mivel az alany erősen kötődik a megfigyelőkhöz, hogy azok aktívak maradjanak. Ezt megelőzhetjük, ha az alanyok csak gyengén kötődnek a megfigyelőkhöz.

Kapcsolódó minták: Közvetítő, Egyke, fel- és leiratkozás.

Kapcsolódás szerkesztés

A megfigyelőt gyakran úgy implementálják, hogy az alany annak az objektumnak a része, aminek az állapotát megfigyelik, és ha szükséges, akkor értesítse a változásról a megfigyelőket. Ez szoros csatolást eredményez, így az alany és a megfigyelők tudnak egymásról, és ami még rosszabb, turkálhatnak egymásban. Ez rontja a sebességet, a skálázhatóságot, a karbantarthatóságot, a biztonságot és a rugalmasságot.[1][2]

Egy másik megvalósítási mód a fel- és leiratkozási minta, ahol üzenetekkel kommunikálnak. Ez tartalmaz egy üzenetsor szervert és egy üzenetkezelőt is. Ez lehetővé teszi, hogy a megfigyelők és az alanyok lazábban kapcsolódjanak, és még csak ne ismerjék egymást, hiszen a üzenetszerver közvetít közöttük. De a fel- és leiratkozás minta máshogy is használható, amivel jelek és értesítések küldhetők; ezzel hasonló eredmény érhető el, a megfigyelő minta használata nélkül.[1][2] Azonban a korai ablakozó rendszerekben még nem különült el a két minta, és szinomimaként használták.[3]

A megfigyelő minta Gammáék könyvében nagyon le van egyszerűsítve. Nem foglalkozik azzal a logikával, amit az alany az üzenet küldése előtt vagy után végez. Nem törődik az üzenetek felhasználásával vagy feljegyzésével. Ezeket rendszerint az üzenetküldő rendszer végzi, aminek a megfigyelő minta a része.

Szerkezet szerkesztés

 

A Megfigyelő minta UML ábrája

Példa szerkesztés

Az alábbi Java példa billentyűzetparancsokat fogad inputként és minden ilyen input sort külön eseményként kezel. A példa a java.util.Observer és a java.util.Observable könyvtárcsoportra épül. Amikor a System.in stringet ad, meghívódik a notifyObservers metódus, mely értesíti a megfigyelőket egy esemény bekövetkeztéről azáltal, hogy meghívja azok ’update’ metódusát, melyet jelen esetben a lambda függvény reprezentál.

import java.util.Observable;
import java.util.Scanner;
 
class EventSource extends Observable implements Runnable {
    public void run() {
        while (true) {
            String response = new Scanner(System.in).next();
            setChanged();
            notifyObservers(response);
        }
    }
}
import java.util.Observable;
import static java.lang.System.out;
 
class MyApp {
    public static void main(String[] args) {
        out.println("Enter Text >");
        EventSource eventSource = new EventSource();
 
        eventSource.addObserver((Observable obj, Object arg) -> { 
            out.println("\nReceived response: " + arg);
        });
 
        new Thread(eventSource).start();
    }
}

Hasonló példa Python-ban:

class Observable:
    def __init__(self):
        self.__observers = []
 
    def register_observer(self, observer):
        self.__observers.append(observer)
 
    def notify_observers(self, *args, **kwargs):
        for observer in self.__observers:
            observer.notify(self, *args, **kwargs)
 
 
class Observer:
    def __init__(self, observable):
        observable.register_observer(self)
 
    def notify(self, observable, *args, **kwargs):
        print('Got', args, kwargs, 'From', observable)
 
subject = Observable()
observer = Observer(subject)
subject.notify_observers('test')

Jegyzetek szerkesztés

  1. a b Comparison between different observer pattern implementations Moshe Bindler, 2015 (Github)
  2. a b Differences between pub/sub and observer pattern The Observer Pattern by Adi Osmani (Safari books online)
  3. The Windows Programming Experience Charles Petzold, Nov 10, 1992, PC Magazine (Google Books)

Kapcsolódó szócikkek szerkesztés