【问题标题】:Having trouble getting the observer pattern working无法让观察者模式正常工作
【发布时间】:2010-11-26 07:35:11
【问题描述】:

我一直试图让观察者模式在一个相对简单的应用程序中工作,但无济于事。

我有 4 个 GUI 类

  • StarterClass(包含CompositeWordListsCompositeWordListData
  • 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); 
    }
}

Observable 接口现在看起来像这样

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);
}

【问题讨论】:

    标签: java observer-pattern


    【解决方案1】:

    您不需要对观察者进行参数化,但您需要对事件进行参数化。

    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();
        }
    }
    

    【讨论】:

    • 谢谢拉尔夫,我会好好看看这个,看看我会怎么做
    • 恕我直言 subject.getWordListObservableRegistration() 这里真的不需要;您可以在内部处理观察者注册所需的额外逻辑。 subject.addObserver() 应该足以让 Subject 类实现 Observable 接口。这也通过了像subject instanceof Observable 这样的逻辑测试。当然,YMMV :)
    • @Sanjay:你是对的,如果主题只有一个 Observable(接口)——但如果有两个或更多(一个用于单词列表,一个用于其他),那么你如果您不想手动实现观察者实现的东西,将会遇到麻烦。 -- 当然你可以在Subject中实现委托方法,但是我相信jax的Observable Interface背后的想法是尽可能少写代码。
    • 我完全同意你的推理;只是 OP 提出的问题没有这样的要求,因此我想出了在给定场景中可能的最简单的解决方案。 :-)
    • 成功了。我不同意@Sanjay,完全理解是一件好事,此外,您从最简单的场景开始并扩展了您的理由,感谢您提供额外的信息,谢谢。
    【解决方案2】:

    我将创建一个 Observer 接口,其中包含一个 public void update(ObservableEvent oe) 方法和一个 ObserverEvent 接口。之后,您可以为每个事件创建特定的类。

    【讨论】:

    • 创建?为什么不直接使用java.util.Observer
    • @Traroth 我尝试了你所说的,但仍然无法正常使用泛型,请参阅我更新的问题
    • @musiKk 因为你必须extend java.util.Observable 并且没有类型安全
    • @musiKk :jax 询问如何实现观察者模式,而不是在哪里可以找到现有的实现。我,一方面,尝试回答实际提出的问题......
    • @jax : 你能描述一下你遇到的问题吗?
    【解决方案3】:

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

    Java Observer 的更新方法有 Object 参数。您可以传递任何对象,因此您可以创建自己的“UpdateMessage”对象,该对象可以包含更新的对象和有关发生情况(删除、保存等)的附加信息。

    【讨论】:

    • 这对 OP 自己的 Observer 实现没有帮助。
    猜你喜欢
    • 2014-02-08
    • 2016-02-20
    • 2023-04-10
    • 2020-02-04
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    相关资源
    最近更新 更多