Dofactory.com
Dofactory.com

C# Proxy Design Pattern

The Proxy design pattern provides a surrogate or placeholder for another object to control access to it. 

C# code examples of the Proxy design pattern is provided in 3 forms:

Frequency of use:
medium-high
C# Design Patterns

UML class diagram

A visualization of the classes and objects participating in this pattern.

Participants

The classes and objects participating in this pattern include:

  • Proxy   (MathProxy)
    • maintains a reference that lets the proxy access the real subject. Proxy may refer to a Subject if the RealSubject and Subject interfaces are the same.
    • provides an interface identical to Subject's so that a proxy can be substituted for for the real subject.
    • controls access to the real subject and may be responsible for creating and deleting it.
    • other responsibilites depend on the kind of proxy:
      • remote proxies are responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a different address space.
      • virtual proxies may cache additional information about the real subject so that they can postpone accessing it. For example, the ImageProxy from the Motivation caches the real images's extent.
      • protection proxies check that the caller has the access permissions required to perform a request.
  • Subject   (IMath)
    • defines the common interface for RealSubject and Proxy so that a Proxy can be used anywhere a RealSubject is expected.
  • RealSubject   (Math)
    • defines the real object that the proxy represents.

Structural code in C#

This structural code demonstrates the Proxy pattern which provides a representative object (proxy) that controls access to another similar object.

using System;

namespace Proxy.Structural
{
    /// <summary>
    /// Proxy Design Pattern
    /// </summary>

    public class Program
    {
        public static void Main(string[] args)
        {
            // Create proxy and request a service

            Proxy proxy = new Proxy();
            proxy.Request();

            // Wait for user

            Console.ReadKey();
        }
    }

    /// <summary>
    /// The 'Subject' abstract class
    /// </summary>

    public abstract class Subject
    {
        public abstract void Request();
    }

    /// <summary>
    /// The 'RealSubject' class
    /// </summary>

    public class RealSubject : Subject
    {
        public override void Request()
        {
            Console.WriteLine("Called RealSubject.Request()");
        }
    }

    /// <summary>
    /// The 'Proxy' class
    /// </summary>

    public class Proxy : Subject
    {
        private RealSubject realSubject;

        public override void Request()
        {
            // Use 'lazy initialization'

            if (realSubject == null)
            {
                realSubject = new RealSubject();
            }

            realSubject.Request();
        }
    }
}

Output
Called RealSubject.Request()

Real-world code in C#

This real-world code demonstrates the Proxy pattern for a Math object represented by a MathProxy object.

using System;

namespace Proxy.RealWorld
{
    /// <summary>
    /// Proxy Design Pattern
    /// </summary>

    public class Program
    {
        public static void Main(string[] args)
        {
            // Create math proxy

            MathProxy proxy = new MathProxy();

            // Do the math

            Console.WriteLine("4 + 2 = " + proxy.Add(4, 2));
            Console.WriteLine("4 - 2 = " + proxy.Sub(4, 2));
            Console.WriteLine("4 * 2 = " + proxy.Mul(4, 2));
            Console.WriteLine("4 / 2 = " + proxy.Div(4, 2));

            // Wait for user

            Console.ReadKey();
        }
    }

    /// <summary>
    /// The 'Subject interface
    /// </summary>

    public interface IMath
    {
        double Add(double x, double y);
        double Sub(double x, double y);
        double Mul(double x, double y);
        double Div(double x, double y);
    }

    /// <summary>
    /// The 'RealSubject' class
    /// </summary>

    public class Math : IMath
    {
        public double Add(double x, double y) { return x + y; }
        public double Sub(double x, double y) { return x - y; }
        public double Mul(double x, double y) { return x * y; }
        public double Div(double x, double y) { return x / y; }
    }

    /// <summary>
    /// The 'Proxy Object' class
    /// </summary>

    public class MathProxy : IMath
    {
        private Math math = new Math();

        public double Add(double x, double y)
        {
            return math.Add(x, y);
        }
        public double Sub(double x, double y)
        {
            return math.Sub(x, y);
        }
        public double Mul(double x, double y)
        {
            return math.Mul(x, y);
        }
        public double Div(double x, double y)
        {
            return math.Div(x, y);
        }
    }
}
Output
4 + 2 = 6
4 - 2 = 2
4 * 2 = 8
4 / 2 = 2

.NET Optimized code in C#

The .NET optimized code demonstrates the same code as above but uses more modern C# and .NET features.

Here is an elegant C# Proxy solution.

namespace Proxy.NetOptimized;

using static System.Console;
using System.Threading;

/// <summary>
/// Proxy Design Pattern
/// </summary>
public class Program
{
    public static void Main()
    {
        // Create math proxy
        var proxy = new MathProxy();

        // Do the math
        WriteLine($"4 + 2 = {proxy.Add(4, 2)}");
        WriteLine($"4 - 2 = {proxy.Sub(4, 2)}");
        WriteLine($"4 * 2 = {proxy.Mul(4, 2)}");
        WriteLine($"4 / 2 = {proxy.Div(4, 2)}");

        // Wait for user
        ReadKey();
    }
}

/// <summary>
/// The 'Subject' interface
/// </summary>
public interface IMath
{
    double Add(double x, double y);
    double Sub(double x, double y);
    double Mul(double x, double y);
    double Div(double x, double y);
}

/// <summary>
/// The 'RealSubject' class
/// </summary>
public class Math : IMath
{
    public double Add(double x, double y) => x + y;
    public double Sub(double x, double y) => x - y;
    public double Mul(double x, double y) => x * y;
    public double Div(double x, double y) => x / y;
}

/// <summary>
/// The remote 'Proxy Object' class
/// </summary>
public class MathProxy : IMath
{
    private readonly Math math = new();

    public double Add(double x, double y)
    {
        Thread.Sleep(800);
        return math.Add(x, y);
    }

    public double Sub(double x, double y)
    {
        Thread.Sleep(800);
        return math.Sub(x, y);
    }

    public double Mul(double x, double y)
    {
        Thread.Sleep(800);
        return math.Mul(x, y);
    }

    public double Div(double x, double y)
    {
        Thread.Sleep(800);
        return math.Div(x, y);
    }
}
Output
4 + 2 = 6
4 - 2 = 2
4 * 2 = 8
4 / 2 = 2



Last updated on Mar 17, 2024

Want to know more?


Learn how to build .NET applications in 33 days with design patterns, ultra clean architecture, and more.

Learn more about our Dofactory .NET developer package.


Guides


vsn 3.2