正常观察者模式与模板观察者模式

时间:2017-08-03 09:25:25

标签: java templates observer-pattern observers

我想知道与模板观察者混淆的观察者模式是否比一般观察者模式更方便。模板观察器的概念是一个可观察的类,它具有作为模板混淆的特定观察者类型。 作为一个例子,我将展示一个普通的观察者并将其与模板观察者进行比较。

普通观察者模式

普通观察者界面:

   public interface NormalObserver {

    //Update method
    void update(final String updateIn);
}

对于实现NormalObserver接口的每个类,update函数都是相同的。当您想要实现特定的观察者时,这会导致问题,例如具有不同更新参数的观察者。

具体观察员:

 public class ConcreteNormalObserver implements NormalObserver {

    //Update implication for NormaObserver interface
    @Override
    public void update(String updateIn) {
        System.out.println(updateIn);
    }
}

普通可观察界面:

 public interface NormalObservable {

    //method for adding an observer
    void addObserver(NormalObserver observerIn);

    //method for removing an observer
    void removeObserver(NormalObserver observerIn);

    //method for notifying observers
    void notifyObservers();

}

具体的正常观察:

    public class ConcreteNormalObservable implements NormalObservable {

    //List for Observer
    private List<NormalObserver> mObservers;

    public ConcreteNormalObservable() {
        this.mObservers = new ArrayList<>();
    }

    @Override
    public void addObserver(NormalObserver observerIn) {

        if(observerIn != null && !this.mObservers.contains(observerIn)) {
            this.mObservers.add(observerIn);
        }
    }

    @Override
    public void removeObserver(NormalObserver observerIn) {
        this.mObservers.remove(observerIn);
    }

    @Override
    public void notifyObservers() {

        for(NormalObserver lObserver: this.mObservers) {
            lObserver.update("Update");
        }
    }
}

在我看来,这是一个直截了当的观察者模式,你可以认为notifyObservers方法有点多余,因为一个observable可以从任何地方的观察者那里调用update方法。

模板观察者模式

模板可观察界面:

  /**
 * @param <ObserverType> Concrete observer to implement in observable,
 * this ObserverType specifies the update functions which the TemplateObservable can call.
 */
public interface TemplateObservable<ObserverType> {

    /**
     * Function to add an Observer of a specific type
     * @param observerIn
     */
    void addObserver(ObserverType observerIn);

    /**
     * Function to remove an Observer of a specific type
     * @param observerIn
     */
    void removeObserver(ObserverType observerIn);

}

模板类型定义您要使用的观察者类型,因此具体的observable指定它将使用哪个观察者。

具体可观察模板:

   /**
 * Concrete example of a class that implements TemplateObservable.
 * This class is uses a ConcreteTemplateObserver as its observerType.n
 */
public class ConcreteTemplateObservable implements TemplateObservable<ConcreteTemplateObserver> {

    //List to hold all the observers
    private List<ConcreteTemplateObserver> mObservers;

    public ConcreteTemplateObservable() {
        this.mObservers = new ArrayList<>();
    }

    @Override
    public void addObserver(ConcreteTemplateObserver observerIn) {

        //Check for non null and if the observer parameter is not already in the observerList
        if(observerIn != null && !this.mObservers.contains(observerIn)) {
            this.mObservers.add(observerIn);
        }
    }

    @Override
    public void removeObserver(ConcreteTemplateObserver observerIn) {
        this.mObservers.remove(observerIn);
    }

    //Own update function, no need for notify function, but can be optional.
    public void update() {

        for(ConcreteTemplateObserver lObserver: this.mObservers) {
            lObserver.updateTemplateObserver("Update");
        }
    }
}

具体模板观察者:

  public class ConcreteTemplateObserver {

    public void updateTemplateObserver(final String messageIn) {
        System.out.println(messageIn);
    }
}

我确信模板观察者模式更有用,因为你可以从observable调用特定的更新函数,而在普通的observable中你被迫使用普通的更新函数,但我怀疑是否模板可观察到了观察者模式的标准。

1 个答案:

答案 0 :(得分:0)

I see very little advantage one way or the other. In practice, an observable object can send several different kinds of notifications, and can also accept several types of observers.

Here is another model that implements once and for all the observer list manipulation, as well as the dispatch mechanism.

Consider the Observable class:

public abstract class Observable {
    private static final Logger LOG
            = Logger.getLogger(Observable.class.getName());
    private final List observers = new ArrayList<>();

    protected void addObserver(Object observer) {
        observers.add(observer);
    }

    protected void removeObserver(Object listener) {
        observers.remove(listener);
    }

    protected <T> T getNotifier(Class<T> intf) {
        ClassLoader cl = intf.getClassLoader();
        return intf.cast(Proxy.newProxyInstance(cl, new Class[] {intf},
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                return dispatch(method, args);
            }
        }));
    }

    protected Object dispatch(Method method, Object args[]) {
        Class<?> intf = method.getDeclaringClass();
        Object result = null;
        for (Object observer: observers) {
            try {
                if (intf.isInstance(observer)) {
                    result = method.invoke(observer, args);
                }
            } catch (IllegalAccessException | InvocationTargetException e) {
                LOG.log(Level.SEVERE, "Error invoking listener method", e);
            }
        }
        return result;
    }
}

Now as an example of how to use it, take an observable list, that accepts observers implementing the following interface:

public interface ListObserver<T> {
    public void elementAdded(int i, T newElem);
    public void elementRemoved(int i, T oldElem);
    public void elementReplaced(int i, T oldElem, T newElem);
}

The observable list would be implemented as follow:

public class ObservableList<T> extends Observable {
    private final List<T> elements = new ArrayList<>();

    private final ListObserver<T> notifier = getNotifier(ListObserver.class);

    public void addObserver(ListObserver<T> obs) {
        super.addObserver(obs);
    }

    public void removeObserver(ListObserver<T> obs) {
        super.removeObserver(obs);
    }

    public void addElement(T newElem) {
        int i = elements.size();
        elements.add(newElem);
        notifier.elementAdded(i, newElem);
    }

    public void removeElement(int i) {
        T oldElem = elements.remove(i);
        notifier.elementRemoved(i, oldElem);
    }

    public void setElement(int i, T newElem) {
        T oldElem = elements.set(i, newElem);
        notifier.elementReplaced(i, oldElem, newElem);
    }
}