Kiedy powinniśmy używać Observer i Observable?

200

Ankieter zapytał mnie:

Co to jest Observeri Observablekiedy powinniśmy ich używać?

I nie był świadomy tych warunków, więc kiedy wróciłem do domu i zaczął googlowanie temat Observeri Observableznalazłem kilka punktów z różnych źródeł:

1) Observablejest klasą i Observerjest interfejsem.

2) ObservableKlasa prowadzi listę Observers.

3) Gdy Observableobiekt jest aktualizowany, wywołuje update()metodę każdego z nich, Observeraby powiadomić o tym, że jest zmieniany.

Znalazłem ten przykład:

import java.util.Observable;
import java.util.Observer;

class MessageBoard extends Observable
{
    public void changeMessage(String message) 
    {
        setChanged();
        notifyObservers(message);
    }
}

class Student implements Observer 
{
    @Override
    public void update(Observable o, Object arg) 
    {
        System.out.println("Message board changed: " + arg);
    }
}

public class MessageBoardTest 
{
    public static void main(String[] args) 
    {
        MessageBoard board = new MessageBoard();
        Student bob = new Student();
        Student joe = new Student();
        board.addObserver(bob);
        board.addObserver(joe);
        board.changeMessage("More Homework!");
    }
}

Ale nie rozumiem, dlaczego potrzebujemy Observeri Observable? Do czego służą setChanged()i notifyObservers(message)metody?

Ravi
źródło
Link nie działa. @Androider Czy możesz podać zaktualizowany link?
prateek
Jeśli używasz języka Java 6 lub nowszego
Ramiz Uddin
1
Gorąco polecam przeczytanie tej książki, aby dobrze zrozumieć wzorce projektowe. Wydaje się to głupie, ale jest doskonałym narzędziem do nauki.
countofmontecristo
1
Pamiętajcie o tym wszyscy; Observer / Observable jest przestarzały w Javie 9. Alternatywy: stackoverflow.com/questions/46380073/…
eren130

Odpowiedzi:

265

Masz konkretny przykład Ucznia i Tablicy Wiadomości. Student rejestruje się, dodając się do listy obserwatorów, którzy chcą otrzymywać powiadomienia, gdy nowa wiadomość zostanie opublikowana na tablicy wyników. Gdy wiadomość jest dodawana do tablicy komunikatów, iteruje się po swojej liście obserwatorów i powiadamia ich o wystąpieniu zdarzenia.

Pomyśl o Twitterze. Gdy mówisz, że chcesz kogoś obserwować, Twitter dodaje Cię do listy obserwujących. Gdy wysłali nowy tweet, widzisz go w swoich danych wejściowych. W takim przypadku Twoim kontem na Twitterze jest Obserwator, a osoba, którą obserwujesz, jest Obserwowalna.

Analogia może nie być idealna, ponieważ Twitter jest bardziej mediatorem. Ale ilustruje to sens.

duffymo
źródło
57

Mówiąc bardzo prosto (ponieważ pozostałe odpowiedzi i tak odnoszą się do wszystkich oficjalnych wzorców projektowych, spójrz na nie, aby uzyskać dalsze szczegóły):

Jeśli chcesz mieć klasę monitorowaną przez inne klasy w ekosystemie twojego programu, mówisz, że chcesz, aby klasa była obserwowalna. Tzn. Mogą wystąpić pewne zmiany w jego stanie, które chciałbyś nadać do reszty programu.

Aby to zrobić, musimy wywołać jakąś metodę. Nie chcemy, aby klasa Obserwowalna była ściśle powiązana z klasami zainteresowanymi jej obserwowaniem. Nie ma znaczenia, kim jest, o ile spełnia określone kryteria. (Wyobraź sobie, że to stacja radiowa, nie ma znaczenia, kto słucha, dopóki mają dostrojone radio FM na swojej częstotliwości). Aby to osiągnąć, korzystamy z interfejsu, zwanego Obserwatorem.

Dlatego klasa Observable będzie miała listę obserwatorów (tj. Instancje implementujące metody interfejsu obserwatora, które możesz mieć). Ilekroć chce coś transmitować, po prostu wywołuje metodę na wszystkich obserwatorach, jeden po drugim.

Ostatnią rzeczą do zamknięcia puzzli jest to, w jaki sposób klasa Obserwowalna będzie wiedzieć, kto jest zainteresowany? Tak więc klasa Obserwowalna musi oferować jakiś mechanizm pozwalający Obserwatorom zarejestrować swoje zainteresowanie. Metoda taka jak addObserver(Observer o)wewnętrzna dodaje obserwatora do listy obserwatorów, dzięki czemu gdy dzieje się coś ważnego, przechodzi przez listę i wywołuje odpowiednią metodę powiadamiania interfejsu obserwatora każdej instancji na liście.

Może się okazać, że w wywiadzie, że nie poprosi o wyraźnie java.util.Observeri java.util.Observabletylko o ogólnej koncepcji. Ta koncepcja jest wzorcem projektowym, który Java zapewnia wsparcie bezpośrednio po wyjęciu z pudełka, aby pomóc Ci szybko go zaimplementować, gdy jest to potrzebne. Proponuję więc, abyś zrozumiał pojęcie, a nie rzeczywiste metody / klasy (które możesz sprawdzić, kiedy ich potrzebujesz).

AKTUALIZACJA

W odpowiedzi na Twój komentarz rzeczywista java.util.Observableklasa oferuje następujące udogodnienia:

  1. Prowadzenie listy java.util.Observerinstancji. Nowe instancje zainteresowane powiadomieniem można dodawać addObserver(Observer o)i usuwać deleteObserver(Observer o).

  2. Utrzymywanie stanu wewnętrznego, określanie, czy obiekt zmienił się od czasu ostatniego powiadomienia obserwatorów. Jest to przydatne, ponieważ oddziela część, w której mówi się, że Observableuległa zmianie, od części, w której powiadamiasz o zmianach. (Np. Jest to użyteczne, jeśli dzieje się wiele zmian i chcesz powiadomić tylko na końcu procesu, a nie na każdym małym kroku). Odbywa się to poprzez setChanged(). Więc po prostu zadzwoń, gdy zmienisz coś na Observablei chcesz, żeby reszta w Observerskońcu o tym wiedziała.

  3. Powiadamianie wszystkich obserwatorów o Observablezmianie stanu określonego. Odbywa się to poprzez notifyObservers(). To sprawdza, czy obiekt rzeczywiście się zmienił (tj. setChanged()Wykonano wywołanie ) przed kontynuowaniem powiadomienia. Istnieją 2 wersje, jedna bez argumentów i jedna z Objectargumentami, na wypadek gdybyś chciał przekazać dodatkowe informacje wraz z powiadomieniem. Wewnętrznie dzieje się tak, że po prostu iteruje listę Observerinstancji i wywołuje update(Observable o, Object arg)metodę dla każdego z nich. Mówi to, Observerktóry obiekt podlegał obserwacji, który się zmienił (możesz obserwować więcej niż jeden), a także dodatkowe, Object argktóre potencjalnie mogą zawierać dodatkowe informacje (przekazywane) notifyObservers().

jbx
źródło
37

Definicja

Wzorzec obserwatora jest używany, gdy istnieje jeden do wielu związków między obiektami, np. Jeśli jeden obiekt jest modyfikowany, jego zależne obiekty mają być powiadamiane automatycznie, a odpowiednie zmiany są wprowadzane we wszystkich obiektach zależnych.

Przykłady

  1. Załóżmy, że Twój stały adres został zmieniony, a następnie musisz powiadomić urząd paszportowy i urząd ds. Karty. Więc tutaj organ paszportowy i organ ds. Kart patelni są obserwatorami, a ty jesteś podmiotem.

  2. Na Facebooku również, jeśli subskrybujesz kogoś, to za każdym razem, gdy pojawią się nowe aktualizacje, zostaniesz o tym powiadomiony.

Kiedy go używać:

  1. Kiedy jeden obiekt zmienia swój stan, wówczas wszystkie inne obiekty zależne muszą automatycznie zmienić swój stan, aby zachować spójność

  2. Gdy badany nie wie o liczbie obserwatorów, którą ma.

  3. Kiedy obiekt powinien móc powiadamiać inne obiekty, nie wiedząc, kim są obiekty.

Krok 1

Utwórz klasę przedmiotów.

Subject.java

  import java.util.ArrayList;
  import java.util.List;

  public class Subject {

  private List<Observer> observers 
        = new ArrayList<Observer>();
  private int state;

  public int getState() {
    return state;
  }

 public void setState(int state) {
   this.state = state;
   notifyAllObservers();
 }

   public void attach(Observer observer){
     observers.add(observer);       
   }

  public void notifyAllObservers(){
    for (Observer observer : observers) {
     observer.update();
  }
}   

}

Krok 2

Utwórz klasę Observer.

Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

Krok 3

Twórz konkretne klasy obserwatorów

BinaryObserver.java

public class BinaryObserver extends Observer{

  public BinaryObserver(Subject subject){
     this.subject = subject;
     this.subject.attach(this);
  }

  @Override
  public void update() {
     System.out.println( "Binary String: " 
     + Integer.toBinaryString( subject.getState() ) ); 
  }

}

OctalObserver.java

public class OctalObserver extends Observer{

   public OctalObserver(Subject subject){
     this.subject = subject;
    this.subject.attach(this);
 }

  @Override
  public void update() {
    System.out.println( "Octal String: " 
    + Integer.toOctalString( subject.getState() ) ); 
  }

}

HexaObserver.java

public class HexaObserver extends Observer{

  public HexaObserver(Subject subject){
    this.subject = subject;
    this.subject.attach(this);
 }

  @Override
  public void update() {
     System.out.println( "Hex String: " 
    + Integer.toHexString( subject.getState() ).toUpperCase() ); 
}

}

Krok 4

Użyj obiektu i konkretnych obiektów obserwatora.

ObserverPatternDemo.java

 public class ObserverPatternDemo {
    public static void main(String[] args) {
       Subject subject = new Subject();

       new HexaObserver(subject);
       new OctalObserver(subject);
       new BinaryObserver(subject);

       System.out.println("First state change: 15");    
       subject.setState(15);
       System.out.println("Second state change: 10");   
       subject.setState(10);
 }

}

Krok 5

Sprawdź dane wyjściowe.

Pierwsza zmiana stanu: 15

Szesnastkowy ciąg: F.

Łańcuch ósemkowy: 17

Ciąg binarny: 1111

Druga zmiana stanu: 10

Szesnastkowy ciąg: A

Łańcuch ósemkowy: 12

Ciąg binarny: 1010

Mubarak
źródło
ładnie wyjaśnione :)
roottraveller
3
Myślę, że „Defination” to literówka. Mam nadzieję, że to literówka.
JohnJoh
10

Są one częścią wzorca projektowego Observer . Zwykle jeden lub więcej obserwatorów zostaje poinformowanych o zmianach w jednym obserwowalnym . Jest to powiadomienie, że „coś” się wydarzyło, w którym jako programista możesz zdefiniować, co znaczy „coś”.

Korzystając z tego wzoru, oddzielasz od siebie obie istoty - obserwatorzy stają się podłączani.

Andy
źródło
Będę wdzięczny, jeśli dodasz wyjaśnienie board.changeMessage("More Homework!");w swojej odpowiedzi, mam na myśli to, co się stanie po changeMessage("More Homework!");wywołaniu.
Ravi
9

Oddzwanianie zwane Observer jest także zarejestrowane w Observable.

Służy do informowania np. O zdarzeniach, które miały miejsce w pewnym momencie. Jest szeroko stosowany w Swing, Ajax, GWT do wysyłania operacji na np. Zdarzeniach interfejsu użytkownika (kliknięcia przycisków, zmienione pola tekstowe itp.).

W Swing znajdziesz metody takie jak addXXXListener (Listener l), w GWT masz wywołania zwrotne (Async).

Ponieważ lista obserwatorów jest dynamiczna, obserwatorzy mogą rejestrować się i wyrejestrowywać w czasie wykonywania. Jest to również dobry sposób na oddzielenie od obserwatora, ponieważ używane są interfejsy.

Paweł Solarski
źródło
9

Jeśli ankieter poprosi o wdrożenie wzorca projektowego Observer bez korzystania z klas i interfejsów Observer, możesz użyć następującego prostego przykładu!

MyObserver jako interfejs obserwatora

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable jako klasa Observable

class MyObservable
{
    ArrayList<MyObserver> myObserverList = new ArrayList<MyObserver>();

    boolean changeFlag = false;

    public void notifyObservers(Object o)
    {
        if (hasChanged())
        {
            for(MyObserver mo : myObserverList) {
                mo.update(this, o);
            }
            clearChanged();
        }
    }


    public void addObserver(MyObserver o) {
        myObserverList.add(o);        
    }

    public void setChanged() {
        changeFlag = true;
    }

    public boolean hasChanged() {
        return changeFlag;
    }

    protected void clearChanged() {
        changeFlag = false;
    }

    // ...
}

Twój przykład z MyObserver i MyObservable!

class MessageBoard extends MyObservable {
  private String message;

  public String getMessage() {
    return message;
  }

  public void changeMessage(String message) {
    this.message = message;
    setChanged();
    notifyObservers(message);
  }

  public static void main(String[] args) {
    MessageBoard board = new MessageBoard();
    Student bob = new Student();
    Student joe = new Student();
    board.addObserver(bob);
    board.addObserver(joe);
    board.changeMessage("More Homework!");
  }
}

class Student implements MyObserver {

  @Override
  public void update(MyObservable o, Object arg) {
    System.out.println("Message board changed: " + arg);
  }

}
Habeeb Perwad
źródło
5

„Próbowałem dowiedzieć się, dlaczego dokładnie potrzebujemy Obserwatora i Obserwowalności”

Jak już wspomniano w poprzednich odpowiedziach, zapewniają one możliwość zasubskrybowania obserwatora, aby otrzymywać automatyczne powiadomienia o obserwowalnym.

Jedną z przykładowych aplikacji, w których może to być przydatne, jest wiązanie danych , powiedzmy, że masz interfejs użytkownika, który edytuje niektóre dane, i chcesz, aby interfejs użytkownika reagował na aktualizację danych, możesz umożliwić obserwowanie danych i subskrybować komponenty interfejsu użytkownika dane

Knockout.js to framework javascript MVVM, który ma świetny samouczek dla początkujących, aby zobaczyć więcej obserwowalnych działań, naprawdę polecam przejrzenie tego samouczka. http://learn.knockoutjs.com/

Znalazłem również ten artykuł na stronie początkowej programu Visual Studio 2008 ( wzorzec obserwatora jest podstawą rozwoju kontrolera Model View (MVC) ) http://visualstudiomagazine.com/articles/2013/08/14/the-observer-pattern-in -net.aspx

Eduardo Wada
źródło
3

Tutaj napisałem krótki opis wzorca obserwatora: http://www.devcodenote.com/2015/04/design-patterns-observer-pattern.html

Fragment posta:

Wzorzec obserwatora: Zasadniczo ustanawia relację jeden do wielu między obiektami i ma luźno powiązany projekt między współzależnymi obiektami.

Definicja podręcznika: Wzorzec obserwatora definiuje zależność jeden do wielu między obiektami, dzięki czemu gdy jeden obiekt zmienia stan, wszystkie jego zależności są powiadamiane i aktualizowane automatycznie.

Rozważmy na przykład usługę powiadamiania o plikach danych. Modele subskrypcji najlepiej zrozumieć wzorzec obserwatora.

Abhishek Jain
źródło
0

Wzorzec obserwatora jest używany, gdy istnieje relacja jeden do wielu między obiektami, np. Jeśli jeden obiekt zostanie zmodyfikowany, jego zależne obiekty mają być powiadamiane automatycznie.

Swapnil Sharma
źródło