在Java中重命名已实现的观察者模式方法

5

我在使用Java中的Observable类/Observer接口来实现观察者模式。Observer接口要求重写update(Observable o, Object arg)方法。

问题是,我正在观察大量的类,我的update()方法变得非常庞大:

public class Foo implements Observer {
    ....

    public void update(Observable o, Object param) {
        if (o instanceof A) {
            // large chunk of code
            ...
        } else if (o instanceof B) {
            // large chunk of code
            ...
        }
            ...
        } else if (o instanceof H) {
            ...
        }
    }

}

为了拆分方法,我考虑扩展观察者接口,例如AObserver接口、BObserver接口等,需要分别重写onAUpdate、onBUpdate等方法。这种方法还可以根据类实现的接口轻松确定它正在观察哪些可观察对象。
class Foo implements AObserver, BObserver {
    ....

    public void onAUpdate(Observable o, Object param) {
        if (o instanceof A) {
        // large chunk of code
        ...
    }

    public void onBUpdate(Observable o, Object param) {
        if (o instanceof B) {
        // large chunk of code
        ...
    }
}

问题在于,如果我继承Observer,我仍然必须实现update()方法。我无法将其重命名为onAUpdate或其他我选择的名称。
有什么建议吗?谢谢。
3个回答

3
我建议创建一个UpdateHandler接口来处理任何给定代码块的处理。每个情况可以使用映射处理。
示例代码如下:
// Interface to implement for each case
public interface UpdateHandler {
    public void update(Observable source, Object data) ;
}

在您的主类中添加一个实例字段,如下所示:

private Map<Class<?>, UpdateHandler> handlers = new HashMap<Class<?>, Update Handler>();

创建一个方法来初始化处理程序。

protected void initializeHandler() {
    handler.put(Integer.class, new IntegerUpdateHandler());
    handler.put(String.class, new StringUpdateHandler());
    ...
}

更新方法将会找到相应的处理程序并分派调用。
public void update(Observable source, Object data)
{
    UpdateHandler handler = handlers.get(data.getClass()) ;
    if (handler == null) 
    {
        // use a default handler ? throw an exception ? your choice ;)
    } else {
        handler.update(source, data) ;
    }
}

这个实现允许你在最小的改动下随时添加新的处理程序。

另一个可能的实现可以基于之前的工作,只需要三步操作。

1)更改处理程序字段的声明。

Map<Class<?>, Class<? extends UpdateHandler>> handlers ;

2) 修改初始化方法

handlers.put(Integer.class, IntegerInputHandler.class);

3) 将主要更新方法更改为创建提供的UpdateHandler实现的新实例。

UpdateHandler handlerInstance = null ;
Class<? extends UpdateHandler> handler = null ;
handler = handlers.get(data.getClass()) ;
...
handlerInstance = handler.newInstance() ;
handlerInstance.update(source, data) ;

我有多个对象观察可观测对象。当发生有趣的事情时,每个查看可观测对象的类的行为都不同。例如,如果Foo和Bar都观察A,当A改变时,Foo这样做,Bar那样做。使用这种方法,这是否意味着我必须为每个对象创建一个处理程序来单独处理更新,例如FooAHandler、BarAHandler? - Justin Wong
@David:如果是这样的话,你不需要任何特殊的东西。默认的ObservableObserver就可以胜任。在你的原始帖子中,你正在检查你的Observable的类型,这表明一个单一的Observer正在观察多个Observable - Adeel Ansari
这是一个多对多的关系 - 多个观察者正在观察多个被观察者。 - Justin Wong

1

将每个条件内的代码块移动到适当命名的方法中。

public void update(Observable o, Object param) {
    if (o instanceof A) {
         onAUpdate(o, param);
    }

    if (o instanceof B) {
         onBUpdate(o, param);
    }
}

public void onAUpdate(Observable o, Object param) {

    // large chunk of code
}

public void onABUpdate(Observable o, Object param) {

    // large chunk of code
}

能否为每个Observable实现一个接口?当它实现AObserver、BObserver等特定的观察者接口时,就可以更清晰地确定我的类对哪些对象感兴趣,而不仅仅是一个通用的Observer。 - Justin Wong
那是他最初正在做的事情。你只是建议将代码块分离到不同的方法中。但代码仍然有问题。 - Adeel Ansari
他描述问题为“我的update()方法变得非常庞大”。 - crnlx
@Sujith:是的,现在问题已经从方法转移到类中了。随着您观察到更多的可观察对象,请添加更多的 if(..instanceof...)。这确实是一种解决方法,但不是非常优雅。 - Adeel Ansari
1
如果您可以将update方法与on<X>Update方法的抽象或默认实现一起推入(抽象)基类中,那么您可以使其更加优雅。 - Stephen C
显示剩余3条评论

1

这里我使用观察者和访问者模式编写了一个原始实现。您可以将其作为一种思路来改进它,并在您认为有空缺的地方进行填充。

public interface IObserver extends Observer {
    public void add(AbstractObservable observable, IObserverVisitor visitor);
    public void remove(AbstractObservable observable);
    public void removeAll();
}

public class Observer implements IObserver {

    Map<AbstractObservable, IObserverVisitor> observableMap =
            new HashMap<AbstractObservable, IObserverVisitor>();

    public void add(AbstractObservable observable, IObserverVisitor visitor) {
        observableMap.put(observable, visitor);
    }

    public void remove(AbstractObservable observable) {
        observableMap.remove(observable);
    }

    public void removeAll() {
        observableMap.clear();
    }

    public void update(Observable o, Object arg) {
        observableMap.get(o).visit(this, o, arg);
    }

}

public class AbstractObservable extends Observable{

    public synchronized void addObserver(IObserver o, IObserverVisitor visitor) {
        o.add(this, visitor);
        super.addObserver(o);
    }

    public synchronized void deleteObservers(IObserver o) {
        o.removeAll();
        super.deleteObservers();
    }

    public synchronized void deleteObserver(IObserver o) {
        o.remove(this);
        super.deleteObserver(o);
    }

    @Override
    public synchronized void deleteObserver(Observer o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public synchronized void addObserver(Observer o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public synchronized void deleteObservers() {
        throw new UnsupportedOperationException();
    }

    @Override
    public synchronized int countObservers() {
        return super.countObservers();
    }

    @Override
    public synchronized boolean hasChanged() {
        return super.hasChanged();
    }

    @Override
    public void notifyObservers() {
        super.notifyObservers();
    }

    @Override
    public void notifyObservers(Object arg) {
        super.notifyObservers(arg);
    }

    @Override
    protected synchronized void clearChanged() {
        super.clearChanged();
    }

    @Override
    protected synchronized void setChanged() {
        super.setChanged();
    }

}

public class Observable1 extends AbstractObservable {
    public void changeSomething() {
      setChanged();
      notifyObservers();
    }
}

public class Observable2 extends AbstractObservable {
    public void changeSomething() {
      setChanged();
      notifyObservers();
    }
}

public interface IObserverVisitor {
    void visit(IObserver obsrvr, Observable obsrvable, Object o);
}

public class ObserverVisitor1 implements IObserverVisitor{

    public void visit(IObserver obsrvr, Observable obsrvable, Object o) {
        System.out.println("updated one");
    }

}

public class ObserverVisitor2 implements IObserverVisitor{

    public void visit(IObserver obsrvr, Observable obsrvable, Object o) {
        System.out.println("updated two");
    }
}

public class ObserverTest {

    @Test
    public void testAnything() {
        Observable1 obsrvable1 = new Observable1();
        Observable2 obsrvable2 = new Observable2();

        Observer obsrvr = new Observer();
        obsrvable1.addObserver(obsrvr, new ObserverVisitor1());
        obsrvable2.addObserver(obsrvr, new ObserverVisitor2());

        obsrvable1.changeSomething();
        obsrvable2.changeSomething();
    }

}

希望你没有迷路。 :)


谢谢,这是一个不错的解决方案。我不确定它是否直接适用于我的情况,我可能需要调整一些部分,但它给了我一些好的想法。 - Justin Wong
@David:很高兴你觉得有帮助。我的努力没有白费。;) - Adeel Ansari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接