Observer Pattern

0

Czytałem ostatnio o wzorcu Observer. Z tego co wyczytałem obiekty sa "loosely coupled ". I dajmy na to mam coś takiego :

public interface Subject {
    void register(Observer observer);
    void unregister(Observer observer);
    void notifyAllObservers();
}

public class PaperShop implements Subject {

    private int costOfBook = 0;
    private int costOfMagazine = 0;

    private ArrayList<Observer> observers;

    public PaperShop() {
        observers = new ArrayList<Observer>();
    }

    @Override
    public void register(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void unregister(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyAllObservers() {
        for(Observer observer:observers)  {
            observer.update(costOfBook, costOfMagazine);
        }
    }

    public void setCostOfBook(int costOfBook) {
        this.costOfBook = costOfBook;
        notifyAllObservers();
    }

    public void setCostOfMagazine(int costOfMagazine) {
        this.costOfMagazine = costOfMagazine;
        notifyAllObservers();
    }
}

public interface Observer {
    void update(int costOfBook, int costOfMagazine);
}

public class House implements Observer {
    private int costOfBook = 0;
    private int costOfMagazine = 0;

    @Override
    public void update(int costOfBook, int costOfMagazine) {
        this.costOfBook = costOfBook;
        this.costOfMagazine = costOfMagazine;
    }

    public int getCostOfBook() {
        return costOfBook;
    }

    public int getCostOfMagazine() {
        return costOfMagazine;
    }
}


i bez problemu moge dodawać kolejne klasy Observer, ale problem pojawia się gdy dodam do klasy implementujacej subject nowe pole np costOfNotebook. Motoda update jest podana tak na "sztywno" . Gdybym miał np tysiąc observerów to w każdej bym musiał ją zmienić. Mógłbym także zrobić w ten sposób :

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

a observera tak :

public class House1 implements Observer {
    private int costOfBook = 0;
    private int costOfMagazine = 0;
    private Subject subject;

    public House1(Subject subject) {
        this.subject = subject;
    }


    @Override
    public void update() {
        costOfBook = subject.getCostOfBook();
        costOfMagazine = subject.getCostOfMagazine();
    }
}

ale teraz każdą metode musze mieć w interfejsie Subject, a przecież Subject może być np sklepem samochodowym i po co implementować metody takie jak costOfBook.

Czy jest jakiś lepszy sposób na rozwiązanie tego ?

0

Metoda notifyAllObservers nie musi lub wrecz nie powinna byc publiczna, wtedy kazdy moze sobie ja wywolac a nie sadze ze tak powinno byc.
Opcji jest kilka:

  1. metoda sama dostaje argumenty z subject - jak zauwazyles, malo elastyczne
  2. metoda dostaje tzw. context i z niego moze sobie sama wybierac informacje - i tak to sie najczesciej robi
    Ten context to moze byc u Ciebie np. Subject, i kazdy listener w metodzie update pobiera z niego odpowiednie dane. Moze to byc rowniez interfejs ktory definiuje gettery - wtedy listened oczekuje implementacji danego interfejsu a nie Subject - jeszcze luzniejsza architektura. W Swingu listenery dostaje Action-obiekty, np. ActionEvent itp., a z nich maja dostep do info, w tym getSource() ktore zwraca referencje do tego kto wyslal powiadomienie.
  3. Mozesz miec wiele metod w interfejsie listenera, kazda oznacza cos innego i bierze rozne dane - to tak naprawde rozwiniecie #1. Taka architekture maja np. delegaty w programowaniu na iOS (iPhone i inne takie). Przy czym dodanie nowej metody sprawi ze bedziesz musial wszystkich implementorow takiego listenera zmienic - dodac implementacje tej metody. Mozna kombinowac z klasa ktora implementuje wszystkie metody jako puste, i wszystkie listenery z niej moga dziedziczyc, ale to nie jest elastyczne i ogolnie nie podoba mi sie ;d

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