2015-07-23 15 views
6

Używam obecnie Java's Observer/Observable Pattern i zastanawiałem się: Dlaczego w obecnej implementacji istnieje potrzeba zastosowania metody setChanged()? Rozumiem, że właśnie tutaj musimy zadzwonić pod numer notifyObservers() jeden raz, pod koniec naszego leczenia.Obserwowalne implementowanie wzorców w Javie

W ten sposób, jeśli chcemy, możemy wycofać wszelkie zmiany za pomocą metody clearChanged(). Mimo to możemy wykonać wszystkie sprawdzenia we własnej implementacji i wywoływać tylko notifyObservers(), gdy chcemy zaktualizować obserwatory.

Prawdopodobnie brakuje mi czegoś, ale nie rozumiem, dlaczego nie uprościło to w ten sposób. Jakieś pomysły?

+0

Pytasz, dlaczego nie zakładali, że twoja implementacja będzie miała określoną funkcjonalność, a zamiast tego zapewni wszystkie narzędzia niezbędne do implementacji rzeczy, jak tylko chcesz? –

+0

@ dave-newton Cóż, w ten sposób, pytanie wydaje się głupie, jasne. Ale bez względu na to, jak to robisz, nadal musisz wykonać sprawdzanie, czy wywołujesz funkcję clearChanged(), czy nie. Dlaczego więc nie zadowalać się aktualizacją przy każdym notifyObservers(), a nie z (pozornie niepotrzebną) flagą setChanged()? – Xalshin

+1

Bo możesz zmieniać rzeczy w każdym miejscu, ale tylko powiadamiać obserwatorów raz na jakiś czas? Np. Na końcu pewnej złożonej logiki biznesowej, która może, ale nie musi, wywoływać 'setChanged()' w procesie wieloetapowym: kiedy to zrobisz, 'notifyObservers()' tylko wtedy, gdy uległa zmianie podczas dowolnego z kroków logiki biznesowej . W ten sposób jedyne "śledzenie zmian", które musisz zrobić, to wywołanie 'setChanged()' i sprawdzenie na końcu. –

Odpowiedz

3

Celem jest oddzielenie oddzielnych spraw. Powiadamiający obserwatorzy mogą być wywoływani w jednym miejscu, a śledzenie zmian odbywa się w innym miejscu. Najczęściej nie potrzebujesz tego rodzaju separacji, ale implementacja java.util.Observable została zaprojektowana tak, aby była w stanie obsłużyć złożone przypadki, w których niekoniecznie istnieje 1-1 zgodność między zmianami a powiadomieniami.

Na przykład możesz mieć wymóg ograniczania przepustowości powiadomień, aby uniknąć zalewania klientów zdarzeniami, które nie powinny wpływać na zmiany śledzenia w momencie ich wystąpienia. W poniższym przykładzie użyto wątku roboczego, który okresowo wywołuje metodę powiadomienia, ale który nie wie o zmianach, oraz inny kod, który akceptuje zmiany, ale nie obsługuje powiadomień.

import java.util.*; 

public class ObservableExample { 

    public static void main(String[] args) throws Exception { 
     CountTracker t = new CountTracker(); 
     t.addObserver(new Observer() { 
      public void update(Observable observable, Object arg) { 
       System.out.println("observed " + arg); 
      } 
     }); 
     t.startNotifying(); 
     for (int i = 0; i < 100; i++) { 
      Thread.sleep(100L); 
      t.incrementCount(); 
     }   
     t.quitNotifying();  
     System.out.println("done");   
    } 
} 

class CountTracker extends Observable {  
    private int count = 0; 
    private Thread notificationThread; 

    public synchronized void incrementCount() { 
     count++; 
     setChanged(); 
    } 

    public synchronized void startNotifying() { 
     if (notificationThread == null || !notificationThread.isAlive()) { 
      notificationThread = new Thread(new Runnable() { 
       public void run() { 
        try { 
         while (!Thread.currentThread().isInterrupted()) { 
          Thread.sleep(1000L); 
          String event = "current value of count is " 
          + CountTracker.this.count; 
          CountTracker.this.notifyObservers(event); 
         } 
        } catch (InterruptedException e) { 
         Thread.currentThread().interrupt(); 
        } 
       } 
      }); 
      notificationThread.start(); 
     } 
    } 

    public synchronized void quitNotifying() throws InterruptedException { 
     if (notificationThread == null || !notificationThread.isAlive()) { 
      return; 
     } 
     notificationThread.interrupt(); 
     System.out.println("wait for notification thread to terminate"); 
     notificationThread.join(); 
    } 
} 

Prawdziwa natura przykład podobny do tego byłoby wdrożenie pasek postępu, który wymaga tłumaczenia skumulowanych nakładów stanowiących zadania coraz zrobić w procentach realizacji i podejmowaniu decyzji, jak często aktualizować wyświetlanie interfejsu użytkownika.

Weź również pod uwagę, że zawsze możesz podklasować java.util.Observable. Twórcy bibliotek JDK nie chcieli obsługiwać dużej liczby subspecjalizacji rzeczy, więc preferowali tworzenie klas, które były tak przydatne jak to tylko możliwe, ale jeśli chcesz wyeliminować pewne nadmiarowość w sposobie korzystania z niego, możesz stworzyć własne zmiana.