4

問題のある (Java) クラス WindowItem があります。メソッドの 1 つがスレッドセーフではありません。WindowItem は外部フレームワークの一部であるため、修正できません。そこで、問題のメソッドに「同期」キーワードを持つデコレータを実装すると考えました。

Decorator は WindowItem を拡張し、WindowItem も含みます。Decorator パターンに従って、Decorator に含まれる WindowItem を呼び出すメソッドを Decorator に作成します。

ただし、WindowItem には、Decorator でオーバーライドできないいくつかの最終メソッドがあります。これにより、Decorator の透明性が損なわれます。これを明示的にしましょう:

public class WindowItem {
   private List<WindowItem> windows;

   public Properties getMethodWithProblem() {
      ...
   }

   public final int getwindowCount() {
      return windows.size();
  }
}

public class WindowItemDecorator extends WindowItem {
   private WindowItem item;

   public WindowItemDecorator(WindowItem item) {
      this.item = item;
   }

   # Here I solve the problem by adding the synchronized keyword:
   public synchronized Properties getgetMethodWithProblem() {
      return super.getMethodWithProblem();
   }

   # Here I should override getWindowCount() but I can't because it's final
}

私自身のコードでは、どこかに WindowItem を渡す必要があるときはいつでも、最初にそれをデコレーターでラップしました: new WindowItemDecorator(item) -- そして、スレッド セーフの問題は消えます。ただし、私のコードが WindowItemDecorator で getwindowCount() を呼び出すと、常にゼロになります。「item」メンバーではなく、スーパークラスで getWindowCount() を実行します。

したがって、WindowItem の設計 (public final メソッドがあるという事実) により、このクラスの Decorator を作成することは不可能になっていると言えます。

それは正しいですか、それとも何か不足していますか?

この場合、ウィンドウのリストのコピーをデコレータに保持して同期を保つことができ、getWindowCount() の結果は正しいでしょう。しかし、その場合、私はフレームワークをフォークしてパッチを当てることを好みます...

4

4 に答える 4

2

このように問題を考えないのはどうでしょうか。のスレッドセーフを想定せずに、コード内のスレッドの問題を処理しないのはなぜですかWindowItem

// I personally prefer ReadWriteLocks, but this sounds like it will do...
synchronized (windowItem) {
    windowItem.getMethodWithProblem();
}

そして、スレッド セーフをより適切にサポートするために、パッケージ メンテナーに RFE を送信します。

実際、クラスがスレッド セーフになるように設計されていない場合、いくつかのsynchronizedキーワードで問題が解決される可能性はほとんどありません。「スレッドセーフ」が意味するものは常に相対的です;-)

(ちなみに、「スレッド対応」バリアントを明示的に使用する代わりに使用しているため、WindowItem間違いなくスレッドセーフではありませんJava で ArrayList を同期する正しい方法- がスレッドセーフな方法でアクセスされているという保証もありません)。ListList

于 2012-08-02T10:00:13.750 に答える
1

おそらく、 Delegation Patternを使用できます。これは、関心WindowItemのあるすべてのメソッドを定義するインターフェイスをクラスが実装している場合にうまく機能します。または、既存のコードをあまり壊さない場合は、WindowItem.

于 2012-08-02T09:53:43.843 に答える
0

あなたの質問に対する答えはイエスです。最終メソッドをオーバーライドすることはできません。つまり、このクラスのデコレーターを作成することはできません。

問題のあるメソッドをオーバーライドし、メソッドを同期することで問題を解決できる場合は、そのままにしておくことができます。つまり、サブクラスのみを使用し、デコレータ パターンは使用しません。

于 2012-08-02T09:44:26.763 に答える
-1

同僚が、私がその問題を解決できると思うアイデアを思いつきました。リスト ウィンドウを変更するすべてのメソッドを調べることで、スーパークラスの状態と "item" メンバーの状態を同期させることができます。いくつかあります: addWindow、removeWindow。デコレーターで単に「item.addWindow(...)」を呼び出す代わりに、スーパークラスでも addWindow を呼び出します。

通常のデコレータ:

public void addWindow(WindowItem newItem) {
   item.addWindow(newItem);
}

この場合、私は次のことを行います。

public void addWindow(WindowItem newItem) {
   super.addWindow(newItem);
   item.addWindow(newItem);
}

これにより、状態が同期され、最終的なメソッドの戻り値が正しくなります。

これは、装飾されているクラスの内部に応じて機能するか機能しないソリューションです。

于 2012-08-02T09:55:02.353 に答える