Software Design Patterns and Principles - Part 9 (Proxy Design Pattern)
Source: Level up coding

Software Design Patterns and Principles - Part 9 (Proxy Design Pattern)


**** Previous Parts ****

Part 1: Introduction

Part 2: List of Most Used Patterns and Singleton Design Pattern

Part 3: Software Design Patterns and Principles - Part 3 (Factory Method and Abstract Factory Method Design Pattern)

Part 4: Software Design Patterns and Principles - Part 4 (Builder Design Pattern)

Part 5: Software Design Patterns and Principles - Part 5 (Adapter Design Pattern)

Part 6: Software Design Patterns and Principles - Part 6 (Decorator Design Pattern)

Part 7: Software Design Patterns and Principles - Part 7 (Composite Design Pattern)

Part 8: Software Design Patterns and Principles - Part 8 (Fa?ade Design Pattern)


Story:

Samiul and Ruhul are two close friends. Samiul is looks handsome and dashing. On the other hand, Ruhul looks black and fatty. But Ruhul has a online girl friend. He is very romantic, they chat everyday. They have a very good relationship in online. But one day the girl wants to meet face to face. In this scenario, Ruhul is in very deep tension because he hasn't enough confidence due to his look. So he decided to send his close and dashing friend Samiul as his Proxy.

Proxy Design Pattern:

Definition:

Proxy is a structural design pattern that lets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original?object.

As the definition stat, Proxy design pattern suggest a middle man approach. Means introduce a substitute of real one and do some sanity, checks, functionality before real one and many more. The main goal is reduce load and secure the main/original object.

Problem:

In the above story, Ruhul don't want to meet directly due his lack of confidence and look. But he wants to maintain the indirect (online relationship). So how can he overcome the meeting day without his direct interaction?

The proxy design pattern is versatile and can be applied in various scenarios to address different concerns. Here are some common scenarios where the proxy design pattern can be used:

  • Virtual Proxy:

Scenario: Loading heavy resources.

Example: Imagine an image gallery where high-resolution images are loaded only when they are viewed. A virtual proxy can be used to represent the high-resolution image, loading it only when the user requests to view it.

  • Protection Proxy:

Scenario: Controlling access to sensitive functionality or data.

Example: In a system where certain users have administrative privileges, a protection proxy can restrict access to certain features or data, ensuring that only authorized users can perform certain actions.

  • Remote Proxy:

Scenario: Accessing objects or services over a network.

Example: When working with distributed systems, a remote proxy can represent an object that resides on a remote server. The proxy handles communication details like network calls, serialization, and deserialization, providing a local representation of the remote object.

  • Cache Proxy:

Scenario: Caching expensive resource accesses.

Example: Consider a web page that fetches data from a remote server. A cache proxy can store the results of expensive queries or network calls, preventing redundant requests by returning the cached data if the same request is made again.

  • Logging Proxy:

Scenario: Logging method calls or interactions.

Example: When debugging or monitoring an application, a logging proxy can wrap around an object or service, capturing information about method calls, input parameters, and results. This can be useful for performance monitoring, auditing, or debugging.

  • Smart Proxy:

Scenario: Adding additional behavior or controlling resource allocation.

Example: Imagine a scenario where you want to limit the number of instances of a resource-heavy object in the system. A smart proxy can manage the instantiation of these objects, ensuring that only a certain number are created or that they are created on-demand.

  • Subject/Observer Proxy:

Scenario: Implementing the observer pattern.

Example: In a system where multiple components need to be notified of changes in another component, a subject/observer proxy can manage the subscription and notification process. Components can subscribe to the proxy, and it can broadcast changes to all subscribers.

  • Immutable Proxy:

Scenario: Ensuring immutability of objects.

Example: If you want to ensure that certain objects cannot be modified after creation, an immutable proxy can wrap around the original object, preventing any modifications. This is particularly useful in scenarios where data integrity and consistency are critical.

These scenarios highlight the flexibility and usefulness of the proxy design pattern in solving different problems across various domains in software development.

Solution:

From the above definition of proxy pattern, it gives us a middle man capability. So in the above story, Ruhul sends/sets Samiul as a proxy/middle man and the issue solve, right?

We can also use or implement proxy pattern as a solution of the problems stated earlier sections as well.

UML Diagram:

Source: Wikipedia

Here in UML diagram we can see that, Clients interacts with the common interface called Subject. And Proxy and RealSubject implements this common interface. Now when client call for DoAction() instead of direct access of RealSubject it first lands to Proxy and then delegate to real one.

When to use:

  1. Lazy initialization (virtual proxy). This is when you have a heavyweight service object that wastes system resources by being always up, even though you only need it from time to time.
  2. Access control (protection proxy). This is when you want only specific clients to be able to use the service object; for instance, when your objects are crucial parts of an operating system and clients are various launched applications (including malicious ones).
  3. Local execution of a remote service (remote proxy). This is when the service object is located on a remote server.
  4. Logging requests (logging proxy). This is when you want to keep a history of requests to the service object.
  5. Caching request results (caching proxy). This is when you need to cache results of client requests and manage the life cycle of this cache, especially if results are quite large.
  6. Smart reference. This is when you need to be able to dismiss a heavyweight object once there are no clients that use it. etc.

Implementation:

// Subject interface
interface Subject {
    void request();
}

// RealSubject class
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}

// Proxy class
class Proxy implements Subject {
    private RealSubject realSubject;

    public void request() {
        // Lazy initialization: create the real subject only when necessary
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        realSubject.request();
    }
}

// Client class
public class Client {
    public static void main(String[] args) {
        System.out.println("Client: Executing the client code with a real subject:");
        RealSubject realSubject = new RealSubject();
        realSubject.request();

        System.out.println("\nClient: Executing the same client code with a proxy:");
        Proxy proxy = new Proxy();
        proxy.request();
    }
}        

Another C# implementation of Proxy design pattern.


Achieved Design Principles:

The Proxy design pattern helps achieve several design principles, enhancing the overall quality, maintainability, and flexibility of the software system. Here are some design principles facilitated by the Proxy pattern:

  1. Single Responsibility Principle (SRP): The Proxy pattern promotes the separation of concerns by introducing a surrogate object to control access to the real object. This allows each component to focus on a single responsibility: the proxy manages access, while the real object performs its core functionality.
  2. Open/Closed Principle (OCP): The Proxy pattern allows for the extension of behavior without modifying the underlying code of the real object. New proxy implementations can be introduced to add additional functionality or behavior without altering the original object's code, thus adhering to the OCP.
  3. Interface Segregation Principle (ISP): By defining a common interface for both the proxy and the real object, the Proxy pattern ensures that clients interact with the proxy in the same way they would with the real object. This promotes a clear and concise interface, adhering to the ISP.
  4. Dependency Inversion Principle (DIP): Clients depend on the abstract interface provided by the proxy, rather than directly depending on the concrete implementation of the real object. This promotes loose coupling between clients and the real object, facilitating easier maintenance and extensibility, in alignment with the DIP.
  5. Encapsulation: The Proxy pattern encapsulates the access to the real object within the proxy, hiding the complexity of accessing or instantiating the real object from clients. This encapsulation promotes information hiding and protects the real object from unauthorized access or misuse.
  6. Reduced Coupling: The Proxy pattern reduces the coupling between clients and the real object by introducing an intermediary (the proxy) to manage interactions. Clients interact with the proxy, which can handle additional concerns such as lazy initialization, caching, or access control, without the client needing to be aware of these details.
  7. Lazy Initialization: Proxies can employ lazy initialization strategies to defer the creation or loading of the real object until it is actually needed. This promotes efficient resource utilization and improves system performance by only initializing objects when necessary.
  8. Performance Optimization: By introducing proxies to manage access to resources, the Proxy pattern enables performance optimizations such as caching, which can reduce the overhead of repeated access to the same resource. This improves system efficiency and responsiveness.

By adhering to these design principles, the Proxy pattern helps developers create software systems that are modular, flexible, maintainable, and efficient, contributing to overall software quality and robustness.


Insha Allah, we finish covering the creational and structural design patterns with that. From the next part we start talking about the behavioral design patterns.


Happy Learning !!!

Happy Coding !!!

Happy Programming !!!

要查看或添加评论,请登录

Saiful Islam Rasel的更多文章

社区洞察

其他会员也浏览了