Javaのオブザーバーパターンの実装方法を変更します
-
27-09-2019 - |
質問
JavaのObservable Class / Observerインターフェイスを使用して、オブザーバーパターンを実装しています。オブザーバーインターフェイスでは、更新(Observable O、Object Arg)メソッドを上書きする必要があります。
問題は、かなりの数のクラスを観察していることであり、更新()方法が非常に大きくなったことです。
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) {
...
}
}
}
メソッドを分割するために、Eg Abserverインターフェイス、Bobserverインターフェイスでオブザーバーインターフェイスを拡張することを考えています。また、この方法により、クラスが実装しているインターフェイスに基づいて観察されている観測可能性を簡単に判断できます。
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
...
}
}
問題は、オブザーバーを継承する場合でも、更新()メソッドを実装する必要があることです。 Onaupdateまたは私の選択の他の名前に名前を変更することはできません。
何かアドバイス?ありがとう。
解決
ここでは、オブザーバーと訪問者のパターンを使用して生の実装をコーディングしました。これを、それを強化し、いくつかの穴を見るところならどこでも埋めるためのアイデアとしてとることができます。
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();
}
}
私はあなたが迷子にならないことを願っています。 :)
他のヒント
特定のコードブロックの処理を行うために、更新ハンドラーインターフェイスを作成することをお勧めします。各ケースは、マップで処理できます。
サンプルコードは次のとおりです。
// 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) ;
}
}
この実装により、必要に応じて最小限の変更で新しいハンドラーを追加できます。
別の可能な実装は、以前の作業に基づいて、わずか3ステップの手順に基づいて行うことができます。
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) ;
各条件内のコードのチャンクを適切に指定されたメソッドに移動します。
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
}