Diagram of the proxy pattern
The Proxy design pattern creates a class as a stand-in for another class that might be too large to instantiate all the time or might be implemented somewhere else. The proxy class knows how to instantiate and talk to the "real" class and typically does so when the first call on the proxy class is made. This allows the proxy class to be instantiated locally but the cost of creating the "real" class is deferred until the proxy class is actually used (called on). There is always a one-to-one relationship between the proxy class and the "real" class.
The key to the proxy class is it has the same interface (methods) as the "real" class. All calls made to the proxy class are forwarded to the "real" class. As far as the local program is concerned, the proxy class is the real class because the two classes look and act the same.
Proxies are most often seen at either end of a communications channel of some kind. For example, in C#, the remoting channel functionality that allows one process to talk to another uses proxy classes on the client end of the remoting channel to represent the real classes on the server end. When a proxy class is instantiated, information about the remoting channel is stashed in the proxy class. When the first call is made on the proxy class, the real class on the server side is instantiated and then the call is forwarded to the real class. The proxy class takes care of communicating across the remoting channel to the real class, where the actual work is done. All of this instantiation is taken care of by C# itself so the client application only sees what it thinks is the real class.
A less well-known use case is when a proxy is used to represent a class that is "expensive" to create and therefore should be deferred until it is actually used. The proxy class is created as usual but as long as it is not actually called on, the "expensive" class is not created. It means the program doesn't have to make any special effort to figure out when to call the "expensive" class.
The proxy class and the "real" class interfaces are the same to help with maintenance. When a new method is added to the "real" class interface, the proxy class also needs to be updated with the new method. If the two classes are in the same process, using an actual interface makes this a lot easier to maintain.
How to Use
This example is really simple: An interface called IWorkByProxy
is implemented on both the Proxy class and the Real class so they match. When the proxy is first called through the IWorkByProxy.DoWork() method, the proxy creates the Real class and forwards the call to the Real class. All subsequent calls to the DoWork() method on the proxy are forwarded to the existing Real class.
C++
void Proxy_Exercise()
{
std::cout << std::endl;
std::cout << "Proxy Exercise" << std::endl;
std::cout << " Getting proxy object..." << std::endl;
std::unique_ptr<IWorkByProxy> proxyObject = Proxy_Classes_Container::CreateProxy();
std::cout << " Calling Dowork() on proxy..." << std::endl;
std::string output = proxyObject->DoWork("Initial call");
std::cout << " Calling Dowork() on proxy..." << std::endl;
output = proxyObject->DoWork("Second call");
std::cout << " Calling Dowork() on proxy..." << std::endl;
output = proxyObject->DoWork("Third call");
std::cout << " Done." << std::endl;
}
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....
C#
public void Run()
{
Console.WriteLine();
Console.WriteLine("Proxy Exercise");
Console.WriteLine(" Getting proxy object...");
IWorkByProxy proxyObject = Proxy_Classes_Container.CreateProxy();
Console.WriteLine(" Calling Dowork() on proxy...");
string output = proxyObject.
DoWork(
"Initial call");
Console.WriteLine(" Output from proxy = \"{0}\"", output);
Console.WriteLine(" Calling Dowork() on proxy...");
output = proxyObject.
DoWork(
"Second call");
Console.WriteLine(" Output from proxy = \"{0}\"", output);
Console.WriteLine(" Calling Dowork() on proxy...");
output = proxyObject.
DoWork(
"Third call");
Console.WriteLine(" Output from proxy = \"{0}\"", output);
Console.WriteLine(" Done.");
}
Represents what can be done on the proxy object. This same interface is implemented on the real objec...
bool(* DoWork)(DynamicString *someArgument)
Does some work on the given argument and updates the given argument.
Python
def Proxy_Exercise():
print()
print("Proxy Exercise")
print(" Getting proxy object...")
proxyObject = Proxy_Classes_Container.CreateProxy()
print(" Calling Dowork() on proxy...")
output = proxyObject.DoWork("Initial call")
print(" Output from proxy = \"{0}\"".format(output))
print(" Calling Dowork() on proxy...")
output = proxyObject.DoWork("Second call")
print(" Output from proxy = \"{0}\"".format(output))
print(" Calling Dowork() on proxy...")
output = proxyObject.DoWork("Third call");
print(" Output from proxy = \"{0}\"".format(output))
print(" Done.")
C
void Proxy_Exercise(void)
{
printf("\nProxy Exercise\n");
printf(" Getting proxy object...\n");
printf(" Calling Dowork() on proxy...\n");
if (success)
{
success = proxyObject->
DoWork(&output);
if (success)
{
printf(
" Output from proxy = \"%s\"\n", output.
string);
}
}
if (success)
{
printf(" Calling Dowork() on proxy...\n");
if (success)
{
success = proxyObject->
DoWork(&output);
if (success)
{
printf(
" Output from proxy = \"%s\"\n", output.
string);
}
}
}
if (success)
{
printf(" Calling Dowork() on proxy...\n");
if (success)
{
success = proxyObject->
DoWork(&output);
if (success)
{
printf(
" Output from proxy = \"%s\"\n", output.
string);
}
}
}
printf(" Done.\n");
}
IWorkByProxy * GetProxyService(void)
Obtain the proxy service.
void DynamicString_Clear(DynamicString *string)
Clear a DynamicString object, releasing any allocated memory. Resets to an empty string.
void DynamicString_Initialize(DynamicString *string)
Initialize a DynamicString object to an empty string.
bool DynamicString_Set(DynamicString *string, const char *s)
Set the DynamicString object to the specified string, replacing whatever is in the DynamicString obje...
Represents a string that can be grown dynamically.
char * string
The string that can grow.
RUST
(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)
pub fn proxy_exercise() -> Result<(), String> {
println!("");
println!("Proxy Exercise");
println!(" Getting proxy object...");
let mut proxy = ProxyEntity::new();
println!(" Calling Dowork() on proxy...");
let mut output = proxy.do_work("Initial call");
println!(" Output from proxy = \"{0}\"", output);
println!(" Calling Dowork() on proxy...");
output = proxy.do_work("Second call");
println!(" Output from proxy = \"{0}\"", output);
println!(" Calling Dowork() on proxy...");
output = proxy.do_work("Third call");
println!(" Output from proxy = \"{0}\"", output);
println!(" Done.");
Ok(())
}
See Also