Introduction
This article talks about Proxy pattern, when should we use proxy pattern and what are the benefits of using the Proxy pattern. This article also presents a small rudimentary implementation of Proxy pattern to illustrate the pattern.
Background
There is sometimes scenarios where we need to access the objects that are either a part of the separate application, separate domain or perhaps are installed on the other part of the world.
If we need to access such objects of functionality we need to handle the communication logic between applications too. i.e. If we need to talk to separate application on same machine then we need IPC. If we need to talk to an application of other machine on same network then Socket programming is needed. If we need to access the application located on the internet then perhaps we need SOAP mechanism to access it.
The whole point of the above scenario illustration is to understand that along with the code/logic to cater to the real functionality/data we need to put in the logic to handle the communication logic too. If we put these two type of logic in same object then this will lead to unmaintainable software. Also, it is little error prone too.
The whole idea of a proxy pattern is to have a local module that will mimic the functionality of the real module. This way the application will deal with this local module as if it only contains the real functionality. All the logic for communicating to the remote module can be put inside this local module i.e. Proxy.
GoF define proxy pattern as "Provide a surrogate or placeholder for another object to control access to it."
To illustrate this design pattern, first look at the class diagram for the pattern.
Let us try to understand each of them one by one
Subject
: This class provides and interface that both actual class and proxy class will implement. this way the proxy can easily be used as substitute for the real subject.
Proxy
: This class will be used by the applications and will expose the methods exposed by the Subject. the application will use this class and this class will internally take care of talking to the RealSubject and get the data to the local application.
RealSubject
: This is the real object that contains the actual logic to retrieve the data/functionality. This is the class that the proxy represents at application end.
Earlier we have seen some superficial categorization for the scenarios where Proxy will be needed. If we need to identify the type of proxies based on the scenarios then we could have three type of proxies.
- Remote proxies: They are responsible for representing the object located remotely. Talking to the real object might involve marshalling and unmarshalling of data and talking to the remote object. All that logic is encapsulated in these proxies and the client application need not worry about them.
-
Virtual proxies: These proxies will provide some default and instant results if the real object is supposed to take some time to produce results. These proxies initiate the operation on real objects and provide a default result to the application. Once the real object is done, these proxies push the actual data to the client where it has provided dummy data earlier.
-
Protection proxies: If an application does not have access to some resource then such proxies will talk to the objects in applications that have access to that resource and then get the result back.
Using the code
Now let us go ahead and try to work out a simple example to see how this pattern can be implemented. We will try to implement a simple application that tries to get the up to date prices of commodities and Dollar value from a remote server. The local application will use a Proxy class that provides simple methods to get these values. The proxy class will internally talk to the server and get the values.
The server for this scenario will typically be a webservice returning values from some database. For the sake of simplicity, I have written the server as a simple application returning hard coded values. The communication between client and server is simple socket programming.
Let us start by looking at the Subject
interface which provides a common interface for proxy
and RealSubject
.
interface IActualPrices
{
string GoldPrice
{
get;
}
string SilverPrice
{
get;
}
string DollarToRupee
{
get;
}
}
Now we have the Subject class ready lets see the implementation of our RealSubject
.
class ActualPrices : IActualPrices
{
public string GoldPrice
{
get
{
return "100";
}
}
public string SilverPrice
{
get
{
return "5";
}
}
public string DollarToRupee
{
get
{
return "50";
}
}
}
These are contained in the server application. The communication logic for the server application is written in the Main
function of server application but this could very well be embedded inside a separate skeleton class to provide more modularity. For now lets assume the Main
function as a part of skeleton class only.
static void Main(string[] args)
{
IPAddress ip = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(ip, 9999);
while (true)
{
listener.Start();
Console.WriteLine("Waiting .....");
Socket s = listener.AcceptSocket();
byte[] b = new byte[100];
int count = s.Receive(b);
string input = string.Empty;
for (int i = 0; i < count; i++)
{
input += Convert.ToChar(b[i]);
}
IActualPrices realSubject = new ActualPrices();
string returnValue = string.Empty;
switch (input)
{
case "g":
returnValue = realSubject.GoldPrice;
break;
case "s":
returnValue = realSubject.SilverPrice;
break;
case "d":
returnValue = realSubject.DollarToRupee;
break;
}
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes(returnValue));
s.Close();
listener.Stop();
Console.WriteLine("Response Sent .....");
}
}
Now we have the server side part of the application ready. Let us now look at the Proxy class that will talk to the RealSubject
.
class ActualPricesProxy : IActualPrices
{
public string GoldPrice
{
get
{
return GetResponseFromServer("g");
}
}
public string SilverPrice
{
get
{
return GetResponseFromServer("s");
}
}
public string DollarToRupee
{
get
{
return GetResponseFromServer("d");
}
}
private string GetResponseFromServer(string input)
{
string result = string.Empty;
using (TcpClient client = new TcpClient())
{
client.Connect("127.0.0.1", 9999);
Stream stream = client.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(input.ToCharArray());
stream.Write(ba, 0, ba.Length);
byte[] br = new byte[100];
int k = stream.Read(br, 0, 100);
for (int i = 0; i < k; i++)
{
result += Convert.ToChar(br[i]);
}
client.Close();
}
return result;
}
}
The important thing to note here is that the Proxy
exposes the same interface as the real subject and encapsulate the communication, marshalling and unmarshalling details in it. This make the client code cleaner and simpler as if it is using the real application.
So if we look at the client application code:
static void Main(string[] args)
{
IActualPrices proxy = new ActualPricesProxy();
Console.WriteLine("Gold Price: ");
Console.WriteLine(proxy.GoldPrice);
Console.WriteLine("Silver Price: ");
Console.WriteLine(proxy.SilverPrice);
Console.WriteLine("Dollar to Ruppe Conversion: ");
Console.WriteLine(proxy.DollarToRupee);
}
Now if we run the Client
application (provided the server application is running already), we can see the output as:
So we can see that the Proxy
class fetches the results from the RealSubject
located in another application and the client
application remain oblivious of the fact that the application exist somewhere else. Before wrapping lets look at the class diagram of our application and compare it with the GoF diagram.
Point of interest
In this article we have tried to see what is Proxy pattern, when could we find it useful. We also saw a rudimentary implementation of proxy pattern in C#. This pattern sometimes looks very similar to decorator and adapter pattern but its not. Decorator adds additional functionality on an object by wrapping the object, the adapter provides a changed interface for the object whereas the proxy pattern provides the same interface as the original object but wraps it to hide the communication and marshalling/unmarshalling details. This article has been written from a beginner's perspective. I hope this has been informative.
History
- 12 November 2012: First version