5


3

デコレータパターンで「this」参照を処理する方法

デコレータパターンを使用する私のクラスに問題があります。

この問題は、内部オブジェクトが他のオブジェクトへの呼び出しで「this」参照を使用するときに発生します。 これにより、「this」参照を受け取ったオブジェクトからのすべての呼び出しが、最初に外部オブジェクトを経由せずに、内部オブジェクトに対して直接行われます。

この問題を解決する通常の方法は何ですか?

ありがとう。

3 Answer


2


オブジェクトには暗黙的な値があります:それらのアイデンティティ( `==`を適用することでテストできます)。 それらをラップすると、そのIDを事実上隠します(さらに悪いことに、潜在的に誤解を招く可能性のあるID、ラッパー自体のIDも公開します)。 したがって、明白なアプローチは、明示的に別の方法でオブジェクトのアイデンティティを公開することにより、これを補います。 E.g. メソッド `Object getIdentity()`を導入すると、目的のIDを実際に表し、 `==`を適用できるオブジェクトを返します。

しかし大きなデメリットは、デコレータ自体でまだ「==」を許可していることです。 次の危険性:

  • それにだまされるのに十分自然です( identity == decorator `identity == decorator.getIdentity()`の代わりに)

  • 静かに間違ったことをします(ランタイム例外と比較-良い 幸運のデバッグ)

たとえば、オブジェクトに次のようなメソッドがある場合、問題は存在しません。

protected Object getIdentity() {
    return this;
}

「==」演算子が定義されるので、ラッパーは、ラップされたオブジェクトを独自のオブジェクトに置き換える代わりに、ラップされたオブジェクトのアイデンティティをラップすることもできます。


1


一般的には、できません。 装飾されたクラスをサブクラス化しない限り、_inner_クラスはそれ自体をパラメーターとして使用して任意のメソッドを自由に呼び出すことができ、変更する方法はありません。

デコレータパターンを使用する場合、デコレータクラスは_this_参照(デコレータ自体を参照)を他のメソッドに渡す役割を担います。 私の観点から見ると、デコレータはプロキシに最も似ています。内部の装飾されたオブジェクトは完全にデコレータにラップされており、直接アクセスできません。 したがって、装飾されたオブジェクトが他のオブジェクトに直接アクセスすることを禁止し、「this」参照を渡すことができる方法を自分で見つけなければなりません


1


あなたが説明しているのは、デコレータとテンプレートパターンのブレンドです。 デコレータパターンを使用すると、(プロキシのようなメカニズムを使用して)オブジェクトに動的に動作を追加できます。 テンプレートパターンはアルゴリズムをいくつかのメソッドに分割するため、サブクラス、または場合によってはデコレータを介してメソッドを置き換えることにより、オブジェクトの動作を変更できます。

デコレータはプロキシの一種であるため、ターゲットオブジェクトへの参照を保持します(または、ターゲットオブジェクトの周囲にn層をラップした別のデコレータ)。 ただし、ターゲットは通常、デコレータを追跡したり、デコレータに関する仮定を行いません。

そのため、最も外側のデコレータを追加または削除することによってターゲットオブジェクトの動作が変更されるたびに、デザインは最も外側のデコレータへの参照でターゲットオブジェクトを更新するか、ターゲットオブジェクトが最も外側のデコレータの参照を別のオブジェクトに照会する必要があります。

ターゲットオブジェクトが、装飾を保持しているオブジェクト(何かが必要)から装飾されたオブジェクトスタックへの参照を照会できる場合は、おそらく大丈夫です。 そうでない場合、ターゲットオブジェクトはデリゲートまたはメディエーターに頼る必要があるかもしれません。