プロキシパターンとデコレータパターンの違い


136

プロキシデコレータの違いは何ですか?

私が目にする主な違いは、プロキシ構成を使用し、デコレータ集約を使用すると仮定すると、複数の(1つ以上の)デコレータを使用することで、既存のインスタンス(装飾)に機能を変更/追加できることは明らかです。プロキシには、プロキシされたクラスの独自の内部インスタンスがあり、それにいくつかの追加機能(プロキシの動作)を追加して委任します。

問題は、- 集約で作成されたプロキシはまだプロキシか、それともデコレータか?(GoFパターンの定義により)集約を使用してプロキシを作成することはできますか?


2
一部のリンク:プロキシおよびデコレータ
Sotirios Delimanolis

5
Proxyがコンポジションを使用し、Decoratorが集約を使用するという考えはどこで得ましたか?
CPerkins 2013

1
@CPerkinsは、Rahul Tripathiの回答に対する私のコメントを参照してください。
ルカシュRzeszotarski

1
また、デコレータ(patterns.cs.up.ac.za/examples/ch2/decorator-theory.cs)-明らかに集約、プロキシ(patterns.cs.up.ac.za/examples/ch2/proxy-theory.cs) -明らかに構成。
hyankov 2016年

回答:


16

これはGoFからの直接の引用です(216ページ)。

デコレータはプロキシと同様の実装を持つことができますが、デコレータには異なる目的があります。デコレータはオブジェクトに1つ以上の責任を追加しますが、プロキシはオブジェクトへのアクセスを制御します。

プロキシは、デコレータのように実装される度合いが異なります。保護プロキシは、デコレータとまったく同じように実装できます。一方、リモートプロキシには、実際のサブジェクトへの直接参照は含まれず、「ホストのホストIDとローカルアドレス」などの間接参照のみが含まれます。仮想プロキシは、ファイル名などの間接参照から始まりますが、最終的には直接参照を取得して使用します。

人気のある回答は、プロキシがそのデリゲートの具体的なタイプを知っていることを示しています。この引用から、それが常に正しいとは限らないことがわかります。

GoFによるプロキシとデコレータの違いは、プロキシがクライアントを制限することです。デコレータにはありません。プロキシは、機能へのアクセスを制御することにより、クライアントの動作を制限する場合があります。または、クライアントからは見えない、不明なアクションを実行することにより、クライアントが知っていることを制限する場合あります。デコレーターは逆のことを行います。それは、デリゲートがクライアントに表示される方法で行うことを強化します。

プロキシはブラックボックスであり、デコレータはホワイトボックスであると言えるかもしれません。

wrapperとdelegateのコンポジション関係は、ProxyとDecoratorを対比するときに焦点を合わせるのに不適切な関係です。コンポジションはこれら2つのパターンに共通する機能であるためです。ラッパーとクライアントの関係は、これら2つのパターンを区別するものです。

  • Decoratorはクライアントに通知し、権限を与えます。
  • プロキシはクライアントを制限し、権限を与えません。

113

実際の違いは、所有権(構成と集約)ではなく、タイプ情報です。

A デコレータされ、常にその委任先を可決しました。A プロキシが ありますそれを自分自身を作成し、または彼がかもしれない、それが注入されています。

しかし、プロキシは 常に(より具体的な)デリゲートのタイプを知っています。つまり、プロキシとそのデリゲートは同じ基本型になりますが、プロキシはいくつかの派生型を指します。A デコレータは、自身の基本型を指します。したがって、違いはデリゲートのタイプに関するコンパイル時の情報にあります。

動的言語では、デリゲートが挿入され、たまたま同じインターフェースを持つ場合、違いはありません。

あなたの質問への答えは「はい」です。


2
「しかし、プロキシは常に(より具体的な)デリゲートのタイプを知っています。」それは本当だとは思いません。リモートプロキシを想像してください。プロキシメカニズムは、リモートオブジェクトの詳細を知る必要はありません。リモートシステムは、指定されたインターフェイスにオブジェクトを登録します。また、ローカルプロキシは同じインターフェイスを公開します。
Alexey

3
私はアマゾンで彼のことを知っている客員講師からこれについてのクラスを受けました。「プロキシ」実行可能ファイル(Webサービスなど)の使用とプロキシ設計パターンには違いがあります。プロキシパターンとデコレータパターンのUMLは異なる場合があります。ただし、プロキシが委任先と同じAPIを持つことを妨げるものはありません。デコレータはプロキシの厳密なサブセットですが、基になるAPIが同じであることが保証されているかどうかによっては、デコレータがプロキシと呼ばれることもあります。
cdunn2001-2015

85

デコレータパターンは、オブジェクトへの関数の動的な追加に重点を置いていますが、プロキシパターンは、オブジェクトへのアクセスの制御に重点を置いています。

編集:-

Proxyと実際のサブジェクトの関係は通常、コンパイル時に設定され、Proxyはそれを何らかの方法でインスタンス化しますが、Decoratorは実行時にサブジェクトに割り当てられ、サブジェクトのインターフェースのみを認識します。


5
ただし、プロキシを使用して機能を追加することもできます。AOPプロキシについて考えてみましょう。
Sotirios Delimanolis 2013

5
完全に同意します。つまり、私がプロキシパターンで意味したことを変換します。プロキシクラスは、オブジェクトの詳細情報をクライアントから隠すことができます。したがって、プロキシパターンを使用する場合、通常はプロキシクラス内にabjectのインスタンスを作成します。また、デコレーターパターンを使用する場合、通常、元のオブジェクトをパラメーターとしてデコレーターのコンストラクターに渡します。
Rahul Tripathi 2013

この場合、プロキシでインスタンスが「非表示」になっていると、(私が書いたように)違いは明らかですが、コンストラクターパラメーターとして渡されたプロキシオブジェクトを受け取るプロキシクラスとして呼び出されることがよくあると思います。この場合、新しい機能を追加したり制御したりすることの違いは(非常に)薄いです。
ルカシュRzeszotarski

5
Proxyと実際のサブジェクトの関係は通常、コンパイル時に設定され、Proxyはそれを何らかの方法でインスタンス化しますが、DecoratorまたはAdapterは実行時にサブジェクトに割り当てられ、サブジェクトのインターフェースのみを認識します。それが理にかなっていると思います!!! :)
Rahul Tripathi 2013

1
この行を回答に追加できますか。
ルカシュRzeszotarski

49

デコレーターながら(通常はコンストラクタを介して)装飾されたオブジェクトのためのget参照プロキシ責任は自分でそれを行います。

プロキシはラッピングオブジェクトをまったくインスタンス化しない可能性があります(オブジェクトフィールド/ゲッターが使用されない場合にDBへの不要なアクセスを防ぐためにORMを実行するなど)一方で、Decoratorは常に実際のラップされたインスタンスへのリンクを保持します。

プロキシは通常、セキュリティまたはキャッシング/レイズを追加するためにフレームワークによって使用され、(通常の開発者自体ではなく)フレームワークによって構築されます。

デコレータは通常、実際のクラスではなくインターフェイスに基づいて、開発者自身が古いクラスまたはレガシークラスに新しい動作を追加するために使用されます(そのため、幅広いインターフェイスインスタンスで機能し、プロキシは具象クラスにあります)。


22

主な違い:

  1. プロキシは同じインターフェースを提供します。Decoratorは拡張されたインターフェースを提供します。
  2. デコレータプロキシの目的は異なりますが、構造は似ています。どちらも、別のオブジェクトへの間接参照のレベルを提供する方法を説明し、実装は、要求の転送先のオブジェクトへの参照を保持します。
  3. デコレータは、コンポーネントが1つしかない縮退したコンポジットと見なすことができます。ただし、Decoratorは追加の責任を追加します- オブジェクトの集約を目的としたものではありません。
  4. デコレーターは再帰的構成をサポートします
  5. デコレータのクラスが宣言組成 LCD(最低クラス分母)インタフェースとの関係を、このデータメンバは、コンストラクタで初期化されます。
  6. プロキシを使用して遅延初期化を行い、オブジェクトをキャッシュしてクライアント/呼び出し元へのアクセスを制御することでパフォーマンスを向上させます

ソースメイキングの記事は類似点と相違点を優れた方法で引用しています。

関連するSEの質問/リンク:

デコレータパターンを使用する場合

アダプターパターンとプロキシパターンの正確な違いは何ですか?


3

プロキシとデコレータは目的が異なり、内部実装に重点を置いています。プロキシは、リモート、クロスプロセス、またはネットワーク間オブジェクトを、ローカルオブジェクトのように使用するためのものです。デコレーターは、元のインターフェースに新しい動作を追加するためのものです。

両方のパターンの構造は似ていますが、プロキシの複雑さの大部分は、ソースオブジェクトとの適切な通信を確保することにあります。一方、Decoratorは、追加された動作の実装に焦点を当てています。


すでにここにある他の4つの回答とは何が違うのですか。
Stephen Rauch、2018

それがすべてあるかどうかはわかりません。以前の答えを読んだ後、チャイムを鳴らしたいという気持ちを感じました。
ジェームズリン

1

この答えとそれが実際に何を意味するのかを理解するのにしばらくかかりました。いくつかの例はそれをより明確にする必要があります。

Proxy 最初:

public interface Authorization {
    String getToken();
} 

そして:

// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
    @Override
    public String getToken() {
        return "DB-Token";
    }
}

そして、これの呼び出し元がAuthorizationあり、かなり馬鹿げています:

class Caller {
    void authenticatedUserAction(Authorization authorization) {
        System.out.println("doing some action with : " + authorization.getToken());
    }
}

これまでに珍しいことはありませんよね?特定のサービスからトークンを取得し、そのトークンを使用します。画像にもう1つの要件が追加されました。ロギングを追加します。つまり、毎回トークンを記録します。この場合は簡単です。単にを作成しますProxy

public class LoggingDBAuthorization implements Authorization {

    private final DBAuthorization dbAuthorization = new DBAuthorization();

    @Override
    public String getToken() {
        String token = dbAuthorization.getToken();
        System.out.println("Got token : " + token);
        return token;
    }
}

それをどのように使用しますか?

public static void main(String[] args) {
    LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();

    Caller caller = new Caller();
    caller.authenticatedUserAction(loggingDBAuthorization);
}

LoggingDBAuthorization のインスタンスを保持していることに注意しくださいDBAuthorization。両方LoggingDBAuthorizationDBAuthorization 実装 Authorization

  • プロキシはDBAuthorization、基本インターフェース(Authorization)のいくつかの具体的な実装()を保持します。つまり、プロキシ何がプロキシされているかを正確に認識しています。

Decorator

Proxyインターフェースはとほぼ同じです。

public interface JobSeeker {
    int interviewScore();
}

そしてその実装:

class Newbie implements JobSeeker  {
    @Override
    public int interviewScore() {
        return 10;
    }
}

次に、より経験豊富な候補者を追加します。これにより、面接スコアと別の候補者のスコアが追加されますJobSeeker

@RequiredArgsConstructor 
public class TwoYearsInTheIndustry implements JobSeeker {

    private final JobSeeker jobSeeker;

    @Override
    public int interviewScore() {
        return jobSeeker.interviewScore() + 20;
    } 
}

私が言ったことをどのように注意してください、他の求職者からのプラスワンではありません Newbie。A Decoratorはそれが何を修飾しているかを正確に知りません、それはその修飾されたインスタンスのコントラクトだけを知っています(それについて知っていますJobSeeker)。これはとは異なることに注意してくださいProxy。対照的に、それはそれが何を飾っているのかを正確に知っています。

この場合、2つのデザインパターンに実際に違いがあるかどうか疑問に思うかもしれません。をDecoratorとして記述しようとするとどうなりProxyますか?

public class TwoYearsInTheIndustry implements JobSeeker {

    private final Newbie newbie = new Newbie();

    @Override
    public int interviewScore() {
        return newbie.interviewScore() + 20;
    }
}

これは間違いなくオプションであり、これらのパターンがどれほど近いかを強調しています。他の回答で説明されているように、それらは異なるシナリオを対象としています。


1

Proxyはラップされたオブジェクトに同じインターフェースを提供し、Decoratorは拡張されたインターフェースを提供します。通常、Proxyはサービスオブジェクトのライフサイクルを独自に管理しますが、Decoratorの構成は常にクライアントによって制御されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.