Implementing the Proxy Pattern in C#

DotNet Full Stack Dev
3 min readJun 29, 2024

--

The Proxy pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. This can be useful for various purposes, such as lazy initialization, access control, logging, and more.

Embark on a journey of continuous learning and exploration with DotNet-FullStack-Dev. Uncover more by visiting our https://dotnet-fullstack-dev.blogspot.com reach out for further information.

Why Use the Proxy Pattern?

  1. Control Access: Restrict access to certain objects.
  2. Lazy Initialization: Delay the creation and initialization of expensive objects until they are actually needed.
  3. Logging: Log requests and responses from objects.
  4. Remote Proxy: Represent objects that are in different address spaces.
  5. Caching: Cache results from expensive operations.

Example Scenario

Let’s consider a scenario where we have a Book class that represents a book in a library system. The Book class has a method GetBookDetails that fetches book details from a database. This operation can be expensive, so we want to use a proxy to control access and add caching to improve performance.

Step-by-Step Implementation

Step 1: Define the Subject Interface

Define an interface that both the real subject and the proxy will implement.

public interface IBook
{
string GetBookDetails(string bookId);
}

Step 2: Create the Real Subject

Create the real subject class that implements the subject interface.

public class Book : IBook
{
public string GetBookDetails(string bookId)
{
// Simulate an expensive operation like fetching data from a database
Console.WriteLine("Fetching book details from database...");
System.Threading.Thread.Sleep(2000); // Simulate delay
return $"Book details for {bookId}";
}
}

Step 3: Create the Proxy Class

Create the proxy class that implements the subject interface and controls access to the real subject.

public class BookProxy : IBook
{
private readonly Book _realBook;
private readonly Dictionary<string, string> _cache;

public BookProxy()
{
_realBook = new Book();
_cache = new Dictionary<string, string>();
}

public string GetBookDetails(string bookId)
{
if (_cache.ContainsKey(bookId))
{
Console.WriteLine("Returning cached book details...");
return _cache[bookId];
}

Console.WriteLine("Fetching book details via proxy...");
var bookDetails = _realBook.GetBookDetails(bookId);
_cache[bookId] = bookDetails;
return bookDetails;
}
}

Step 4: Use the Proxy in the Application

Use the proxy in the application to control access to the real subject and add caching.

class Program
{
static void Main()
{
IBook bookProxy = new BookProxy();

// First call, fetches from the database
Console.WriteLine(bookProxy.GetBookDetails("1"));

// Second call, returns cached details
Console.WriteLine(bookProxy.GetBookDetails("1"));

// Fetches new book details from the database
Console.WriteLine(bookProxy.GetBookDetails("2"));
}
}

Detailed Explanation

  1. Subject Interface (IBook): This interface defines the method GetBookDetails that both the real subject and the proxy will implement. It ensures that the proxy can be used in place of the real subject.
  2. Real Subject (Book): The Book class implements the IBook interface and provides the actual implementation of the GetBookDetails method. This method simulates an expensive operation by adding a delay.
  3. Proxy (BookProxy): The BookProxy class also implements the IBook interface. It contains an instance of the real subject (Book) and a cache to store the results of previous requests. The GetBookDetails method in the proxy first checks the cache. If the details are already cached, it returns the cached details. Otherwise, it calls the real subject's method, caches the result, and then returns the details.
  4. Application (Program): In the Main method, we use the BookProxy to get book details. The first call to GetBookDetails fetches the details from the database and caches them. The second call returns the cached details, avoiding the expensive database operation. The third call fetches new book details for a different book and caches them.

Conclusion

The Proxy pattern is a versatile design pattern that can be used to control access to objects, add caching, lazy initialization, and more. By implementing a proxy, you can optimize performance and manage resources efficiently. This pattern is especially useful in scenarios where object creation is expensive, access needs to be controlled, or operations need to be logged or monitored.

--

--

DotNet Full Stack Dev
DotNet Full Stack Dev

Written by DotNet Full Stack Dev

Join me to master .NET Full Stack Development & boost your skills by 1% daily with insights, examples, and techniques! https://dotnet-fullstack-dev.blogspot.com

No responses yet