私はプロキシパターンを見ていましたが、デコレータ、アダプタ、ブリッジパターンに非常によく似ているように見えます。私は何かを誤解していますか?違いは何ですか?なぜプロキシパターンを他のパターンと比較して使用するのですか?過去に実際のプロジェクトでそれらをどのように使用しましたか?
13 に答える
Proxy、Decorator、Adapter、および Bridge はすべて、クラスの「ラッピング」のバリエーションです。しかし、それらの用途は異なります。
プロキシは、オブジェクトを遅延インスタンス化する場合、またはリモート サービスを呼び出しているという事実を非表示にする場合、またはオブジェクトへのアクセスを制御する場合に使用できます。
デコレータは「スマート プロキシ」とも呼ばれます。これは、オブジェクトに機能を追加したいが、そのオブジェクトのタイプを拡張したくない場合に使用されます。これにより、実行時にこれを行うことができます。
アダプターは、抽象的なインターフェースがあり、そのインターフェースを、同様の機能的役割を持つが異なるインターフェースを持つ別のオブジェクトにマップする場合に使用されます。
Bridgeは Adapter と非常に似ていますが、抽象インターフェースと基礎となる実装の両方を定義する場合、Bridge と呼びます。つまり、一部のレガシー コードやサードパーティ コードに適応するのではなく、すべてのコードの設計者ですが、さまざまな実装を交換できる必要があります。
Facadeは、1 つまたは複数のクラスのサブシステムへの高レベル (読み方: より単純) なインターフェイスです。複数のオブジェクトを表す必要がある複雑な概念があるとします。オブジェクトのセットに変更を加えるのは混乱を招きます。呼び出す必要のあるメソッドがどのオブジェクトに含まれているかを常に把握しているわけではないからです。オブジェクトのコレクションに対して実行できるすべての複雑な操作に対応する高レベルのメソッドを提供する Facade を作成するときです。
countStudents()
例: 、reportAttendance()
、などのメソッドを使用した、学校のセクションのドメイン モデルassignSubstituteTeacher()
。
それらの構造も同様です。
ProxyとDecoratorはどちらもラップされた型と同じインターフェイスを持ちますが、proxy は内部でインスタンスを作成しますが、decorator はコンストラクターでインスタンスを取ります。
AdapterとFacadeはどちらも、ラップするものとは異なるインターフェイスを持っています。ただし、アダプターは既存のインターフェースから派生しますが、ファサードは新しいインターフェースを作成します。
BridgeとAdapterはどちらも既存の型を指しています。ただし、ブリッジは抽象型を指し、アダプターは具象型を指す場合があります。ブリッジを使用すると、実行時に実装をペアリングできますが、アダプターは通常そうではありません。
多くの GoF パターンには多くの重複があります。それらはすべてポリモーフィズムの力に基づいて構築されており、実際には意図が異なるだけの場合もあります。(戦略対国家)
Head First Design Patternsを読んだ後、パターンに対する私の理解は 100 倍になりました。
強くお勧めします!
それらは非常に似ており、それらの間の線はかなり灰色です. c2 wikiのProxy PatternとDecorator Patternのエントリを読むことをお勧めします。
そこにあるエントリと議論は非常に広範であり、他の関連記事へのリンクも含まれています。ところで、異なるパターン間のニュアンスについて疑問に思っているときは、c2 wiki が優れています。
c2 エントリをまとめると、デコレータは動作を追加/変更しますが、プロキシはアクセス制御 (遅延インスタンス化、リモート アクセス、セキュリティなど) にもっと関係があると言えます。しかし、私が言ったように、それらの間の線は灰色であり、簡単にデコレーターと見なすことができるプロキシへの参照があり、その逆も同様です。
Webサービスを利用するときによく使用します。プロキシパターンは、おそらく「ラッパーパターン」など、より実用的な名前に変更する必要があります。MSExcelのプロキシであるライブラリもあります。これにより、Excelの自動化が非常に簡単になり、背景の詳細などを気にする必要がなくなります。バージョンがインストールされています(存在する場合)。
コードが明確なアイデアを提供すると信じています(他の回答も補完するため)。以下を参照してください(クラスが実装およびラップするタイプに注目してください)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
/* Proxy */
Console.WriteLine(Environment.NewLine);
Console.WriteLine("PROXY");
Console.WriteLine(Environment.NewLine);
//instead of creating here create using a factory method, the facory method will return the proxy
IReal realProxy = new RealProxy();
Console.WriteLine("calling do work with the proxy object ");
realProxy.DoWork();
Console.WriteLine(Environment.NewLine);
Console.WriteLine("ADAPTER");
Console.WriteLine(Environment.NewLine);
/*Adapter*/
IInHand objectIHave = new InHand();
Api myApi = new Api();
//myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */
IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave);
Console.WriteLine("calling api with my adapted obj");
myApi.SomeApi(myAdaptedObject);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("DECORATOR");
Console.WriteLine(Environment.NewLine);
/*Decorator*/
IReady maleReady = new Male();
Console.WriteLine("now male is going to get ready himself");
maleReady.GetReady();
Console.WriteLine(Environment.NewLine);
IReady femaleReady = new Female();
Console.WriteLine("now female is going to get ready her self");
femaleReady.GetReady();
Console.WriteLine(Environment.NewLine);
IReady maleReadyByBeautician = new Beautician(maleReady);
Console.WriteLine("now male is going to get ready by beautician");
maleReadyByBeautician.GetReady();
Console.WriteLine(Environment.NewLine);
IReady femaleReadyByBeautician = new Beautician(femaleReady);
Console.WriteLine("now female is going to get ready by beautician");
femaleReadyByBeautician.GetReady();
Console.WriteLine(Environment.NewLine);
Console.ReadLine();
}
}
/*Proxy*/
public interface IReal
{
void DoWork();
}
public class Real : IReal
{
public void DoWork()
{
Console.WriteLine("real is doing work ");
}
}
public class RealProxy : IReal
{
IReal real = new Real();
public void DoWork()
{
real.DoWork();
}
}
/*Adapter*/
public interface IActual
{
void DoWork();
}
public class Api
{
public void SomeApi(IActual actual)
{
actual.DoWork();
}
}
public interface IInHand
{
void DoWorkDifferently();
}
public class InHand : IInHand
{
public void DoWorkDifferently()
{
Console.WriteLine("doing work slightly different ");
}
}
public class ActualAdapterForInHand : IActual
{
IInHand hand = null;
public ActualAdapterForInHand()
{
hand = new InHand();
}
public ActualAdapterForInHand(IInHand hnd)
{
hand = hnd;
}
public void DoWork()
{
hand.DoWorkDifferently();
}
}
/*Decorator*/
public interface IReady
{
void GetReady();
}
public class Male : IReady
{
public void GetReady()
{
Console.WriteLine("Taking bath.. ");
Console.WriteLine("Dress up....");
}
}
public class Female : IReady
{
public void GetReady()
{
Console.WriteLine("Taking bath.. ");
Console.WriteLine("Dress up....");
Console.WriteLine("Make up....");
}
}
//this is a decorator
public class Beautician : IReady
{
IReady ready = null;
public Beautician(IReady rdy)
{
ready = rdy;
}
public void GetReady()
{
ready.GetReady();
Console.WriteLine("Style hair ");
if (ready is Female)
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("doing ready process " + i);
}
}
}
}
}
詳細な実装について言えば、Proxy と Decorator、Adapter、Facade の違いを見つけます。これらのパターンの一般的な実装では、囲んでいるオブジェクトによってラップされたターゲット オブジェクトがあります。クライアントは、ターゲット オブジェクトの代わりに囲みオブジェクトを使用します。そして、ターゲットオブジェクトは、オブジェクトを囲むメソッドのいくつかの中で実際に重要な役割を果たします。
ただし、プロキシの場合、囲んでいるオブジェクトはそれ自体でいくつかのメソッドを実行できます。クライアントがターゲット オブジェクトが参加する必要があるいくつかのメソッドを呼び出すと、ターゲット オブジェクトを初期化するだけです。これは遅延初期化です。それ以外のパターンの場合、対象オブジェクトを仮想的に囲い込みます。したがって、ターゲット オブジェクトは常に、コンストラクター/セッターで囲んでいるオブジェクトと共に初期化されます。
別のこととして、プロキシはターゲットとまったく同じことを行いますが、他のパターンはターゲットにより多くの機能を追加します。