wzorzec observer - jeden obserwator, kilka subjectów?

0

Witam,

Potrzebuję pomocy z rozwiązaniem pewnego problemu. Planuję wykorzystać wzorzec obserwer dla paska Statusu (projektuję edytor obrazów wektorowych). Trafiłem jednak na pewien problem - potrzebuję mieć możliwość, żeby kilka subjectów (w moim przypadku JPaneli) informowało obserwator (StatusBarPanel) o zmianach na nich wykonywanych.

Mam jeden główny JPanel, który póki co jest Subjectem (Observable) i kilka innych paneli, które trzymają referencję do tego rodzica i mogą dzięki temu imitować bycie Subjectami. Takie rozwiązanie jednak chyba trochę się kłóci z założeniami wzorca, bo zależności subject - observer powinny być jasno zdefiniowane.

Sub sub = new Sub();        //DrawPanel
        Obs obs = new Obs();        //StatusBarPanel
        sub.addObserver(obs);
        A a = new A(sub);           //BrushOptionsPanelActionListener
        B b = new B(sub);           //PaintOptionsPanelActionListener
        C c = new C(sub);           //...
        a.setState("Klasa A v2");

Póki co wygląda to tak, jednak chciałbym to jakoś zmodyfikować tak, żeby każda z tych klas (A, B, C) mogła informować jednego obserwatora (obs). Czy istnieje taka możliwość? Czy nie wychodzi to poza założenia wzorca?

Pozdrawiam,
Marcin

1

Niech Observable będzie interfejsem:

public interface Observable{
    void add(Observer o);
    void informAll();
}

Wtedy wystarczy by A, B i C implementowały ten interfejs. Można w takim przypadku:

Oberserver o = new ObserverImpl();
sub.add(o);
a.add(o);
b.add(o);
c.add(o);

należy tylko zrobić sobie podwójną synchronizację w metodzie informAll(). Pierwszy lock nakładasz na obiekt obserwowany, drugi w pętli na konkretnego obserwatora.

0

Czyli każda z tych klas ma być subjectem? Myślałem, że da się jakoś zrobić Wrappera / Managera do takich zastosowań, chociaż to rozwiązanie nie jest takie złe. Bardzo zależy mi na tym, żeby to wciąż był wzorzec obserwator, a nie jakieś moje wariacje (projekt na programowanie obiektowe 2).

Koziołek napisał(a)

należy tylko zrobić sobie podwójną synchronizację w metodzie informAll(). Pierwszy lock nakładasz na obiekt obserwowany, drugi w pętli na konkretnego obserwatora.

Możesz jakoś rozwinąć tą wypowiedź? Wiem o co chodzi z tą synchronizacją, ale nigdy nie miałem potrzeby implementacji (no chyba, że mutexy na SO :)).

Dziękuję i Pozdrawiam

1

Generalnie chodzi o to by nie dopuścić do sytuacji zaspamowania obserwatorów lub wprowadzenia ich w stan nieokreślony:

// Synchronizacja w tym miejscu by odpalać metodę tylko raz na raz. Kolejne zmiany stanu będą kolejkowane.
public synchronized void informAll(){
  for(Observer o : observers){
      // Dodatkowo blokujemy konkretnego obserwatora tak by różne Subjecty nie mogły na raz go zmieniać i nie doprowadziły do stanu nieustalonego.
      synchronize(o){
          o.update(this);
      }
  }
}
0

Dziękuję ślicznie za pomoc :)

Pozdrawiam,
Marcin

1 użytkowników online, w tym zalogowanych: 0, gości: 1