Возникли проблемы с работой шаблона наблюдателя - PullRequest
2 голосов
/ 26 ноября 2010

Я пытался безрезультатно заставить шаблон наблюдателя работать в относительно простом приложении.

У меня есть 4 класса GUI

  • StarterClass (содержит CompositeWordLists и CompositeWordListData)
  • CompositeWordLists (содержит много CompositeListItem / s и CompositeWordListData)
    • CompositeListItem
  • CompositeWordListData (содержит DialogWordData)
    • DialogWordData

Вот мой Observable

interface Observable<T> {
    void addObserver(T o);
    void removeObserver(T o);
    void removeAllObservers();
    void notifyObservers();
}

И я создаю Обозреватели вот так:

public class Observers {
    private Observers(){};

    interface WordListsObserver {
        public void update(CompositeWordLists o);
    }   

    interface ListItemObserver {
        public void update(CompositeListItem o);
    }
}

В основном у меня возникают проблемы с указанием типа события, которое произошло.Например, класс CompositeWordLists должен знать, когда CompositeListItem удален, сохранен, отредактирован и т. Д., Но у меня есть только один метод обновления ... у меня сейчас болит мозг!

Как лучше это сделать?


ОБНОВЛЕНИЕ

Все еще испытывая проблемы с этим, я добавил события и изменил Observable и Observers, но теперь у меня есть типпроблемы безопасности.

public class Observers {
    private Observers(){};

    /**
     * @param <T> the object that is passed from the Observable
     */
    interface ObservableEvent<T> {
        T getEventObject();
    }


    /**
     * Get notified about Authentication Attempts
     */
    interface ObserverAuthenticationAttempt {
        /**
         * @param e true if authentication was successful
         */
        public void update(ObservableEvent<Boolean> e); 
    }


    /**
     * Get notified about a Word Deletion
     */
    interface ObserverWordDeleted {
        /**
         * @param e the id of the word that was deleted
         */
        public void update(ObservableEvent<Integer> e); 
    }
}

Наблюдаемый интерфейс теперь выглядит следующим образом

interface Observable<T> {
    void addObserver(T o);
    void removeObserver(T o);
    void removeAllObservers();
    <K> void  notifyObservers(Observers.ObservableEvent<K> e);
}

Проблема заключается в том, что когда я его реализую, я получаю и должен приводить K к соответствующему типу, а недействительно, что я хочу сделать.

@Override
public <K> void notifyObservers(ObservableEvent<K> e) {
    for(Observers.ObserverAuthenticationAttempt o : this.observers)
        o.update(e);
}

Что я делаю не так?

обновление 2

На самом деле это работает лучше с Observable, как это, но мне все еще нужночтобы указать правильный EventType в двух разных местах.

interface Observable<T,K> {
    void addObserver(T o);
    void removeObserver(T o);
    void removeAllObservers();
    void  notifyObservers(Observers.ObservableEvent<K> e);
}

Ответы [ 3 ]

3 голосов
/ 26 ноября 2010

Вам не нужно параметризировать Наблюдатели, но вам нужно параметризовать события.

public interface Observer<T> {
    void notify(T event);
}

Пример события:

public class WordListUpateEvent {

    private final int changedIndex;

    public WordListUpateEvent(int changedIndex) {       
        this.changedIndex = changedIndex;
    }

    public int getChangedIndex() {
        return changedIndex;
    }
}

Тогда вы можете иметь другой интерфейс, например:

public interface WordListObserver extends Observer<WordListUpateEvent> {}

и его реализации

public class ConcreteWordListObserverA implements WordListObserver {
    @Override
    public void notify(WordListUpateEvent event) {
        System.out.println("update item at index: " + event.getChangedIndex());
    }
}

с другой стороны, вам нужен ваш интерфейс Observable, я разделил его на два интерфейса, чтобы сделать метод notifyObservers закрытым для наблюдателей (вы увидите это позже):

public interface Observable<T> extends ObservableRegistration<T> {  
    void notifyObservers(T event);
}

public interface ObservableRegistration<T> {

    void addObserver(Observer<T> o);
    void removeObserver(Observer<T> o);
    void removeAllObservers();
}

Если у вас есть несколько наблюдаемых в теме, вы не можете реализовать интерфейс Observalbe непосредственно для вашей темы, поэтому вам нужен отдельный класс реализации:

public class ObservableImpl<T> implements Observable<T>{

    private final List<Observer<T>> observers = new ArrayList<Observer<T>>();

    @Override
    public void addObserver(Observer<T> o) {
        this.observers.add(o);
    }

    @Override
    public void removeObserver(Observer<T> o) {
        this.observers.remove(o);
    }

    @Override
    public void removeAllObservers() {
        this.observers.clear();     
    }

    @Override
    public void notifyObservers(T event) {      
        for(Observer<T> observer : observers) {
            observer.notify(event);
        }
    }

}

Теперь вы можете использовать реализацию в вашей теме:

public class Subject {

    private Observable<WordListUpateEvent> wordListObservable = new ObservableImpl<WordListUpateEvent>(); 

    //private Subject<OtherEvent> otherObservable = new ObservableImpl<WordListUpateEvent>();


    public ObservableRegistration<WordListUpateEvent> getWordListObservableRegistration() {
        return this.wordListObservable;
    }

//  public ObservableRegistration<OtherEvent> getOtherRegistration() {
//      return this.otherObservable;
//  }

    public void doSomething() {
        this.wordListObservable.notifyObservers(new WordListUpateEvent(42));
    }

}

А вот как вы можете соединить наблюдателя и субъекта:

public class Start {

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

        subject.getWordListObservableRegistration().addObserver(new ConcreteWordListObserverA());
        subject.getWordListObservableRegistration().addObserver(new ConcreteWordListObserverA());

        subject.doSomething();
    }
}
0 голосов
/ 26 ноября 2010

http://download.oracle.com/javase/1.4.2/docs/api/java/util/Observer.htmlhttp://www.java2s.com/Code/Java/Design-Pattern/Observableandobserver.htm

У метода обновления Java Observer есть аргумент Object.Вы можете передать любой объект, таким образом, вы можете создать свой собственный объект «UpdateMessage», который может содержать обновленный объект и дополнительную информацию о том, что произошло (удалено, сохранено и т. Д.).

0 голосов
/ 26 ноября 2010

Я бы создал интерфейс Observer, содержащий метод public void update(ObservableEvent oe) и интерфейс ObserverEvent. После этого вы можете создать определенный класс для каждого из ваших событий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...