
Proxy を C# で
Proxy は、 構造に関するデザインパターンの一つで、 クライアントが使う本物のサービス・オブジェクトの代理として機能するオブジェクト (プロキシー) を提供します。 プロキシーは、 アクセス制御、 キャッシングなど、 何らかの作業を行なった後、 リクエストをサービス・オブジェクトに渡します。
プロキシー・オブジェクトはサービスと同じインターフェースを持ち、 クライアントにとっては、 本物のオブジェクトと交換可能です。
複雑度:
人気度:
使用例: Proxy パターンは、 ほとんどの C# アプリケーションにおいては、 あまり見かけませんが、 いくつかの特殊なケースでは便利です。 何らかの既存クラスのオブジェクトに何らかの振る舞いを追加したいがクライアント・コードには手を加えたくない時、 かけがえのないものです。
見つけ方: プロキシーは、 実際の作業はすべて他のオブジェクトに委任します。 プロキシーがサービスのサブクラスである場合を除き、 プロキシーのメソッドのそれぞれは、 最終的にはサービス・オブジェクトを参照するはずです。
概念的な例
この例は、 Proxy デザインパターンの構造を説明するためのものです。 以下の質問に答えることを目的としています:
- どういうクラスからできているか?
- それぞれのクラスの役割は?
- パターンの要素同士はどう関係しているのか?
Program.cs: 概念的な例
using System; namespace RefactoringGuru.DesignPatterns.Proxy.Conceptual { // The Subject interface declares common operations for both RealSubject and // the Proxy. As long as the client works with RealSubject using this // interface, you'll be able to pass it a proxy instead of a real subject. public interface ISubject { void Request(); } // The RealSubject contains some core business logic. Usually, RealSubjects // are capable of doing some useful work which may also be very slow or // sensitive - e.g. correcting input data. A Proxy can solve these issues // without any changes to the RealSubject's code. class RealSubject : ISubject { public void Request() { Console.WriteLine("RealSubject: Handling Request."); } } // The Proxy has an interface identical to the RealSubject. class Proxy : ISubject { private RealSubject _realSubject; public Proxy(RealSubject realSubject) { this._realSubject = realSubject; } // The most common applications of the Proxy pattern are lazy loading, // caching, controlling the access, logging, etc. A Proxy can perform // one of these things and then, depending on the result, pass the // execution to the same method in a linked RealSubject object. public void Request() { if (this.CheckAccess()) { this._realSubject.Request(); this.LogAccess(); } } public bool CheckAccess() { // Some real checks should go here. Console.WriteLine("Proxy: Checking access prior to firing a real request."); return true; } public void LogAccess() { Console.WriteLine("Proxy: Logging the time of request."); } } public class Client { // The client code is supposed to work with all objects (both subjects // and proxies) via the Subject interface in order to support both real // subjects and proxies. In real life, however, clients mostly work with // their real subjects directly. In this case, to implement the pattern // more easily, you can extend your proxy from the real subject's class. public void ClientCode(ISubject subject) { // ... subject.Request(); // ... } } class Program { static void Main(string[] args) { Client client = new Client(); Console.WriteLine("Client: Executing the client code with a real subject:"); RealSubject realSubject = new RealSubject(); client.ClientCode(realSubject); Console.WriteLine(); Console.WriteLine("Client: Executing the same client code with a proxy:"); Proxy proxy = new Proxy(realSubject); client.ClientCode(proxy); } } }
Output.txt: 実行結果
Client: Executing the client code with a real subject: RealSubject: Handling Request. Client: Executing the same client code with a proxy: Proxy: Checking access prior to firing a real request. RealSubject: Handling Request. Proxy: Logging the time of request.