About a design pattern
Design patterns represent the best repeatable solutions used by experienced object-oriented software developers. Design patterns are practices to common issues in software design. Various software developers have been hit-and-miss and finally collected these solutions over quite a considerable period. A design pattern is an unfinished design that can be transformed directly into code. It is a sketch or template for how to deal with an issue that can be adapted to numerous situations.
The importance of design patterns
Design patterns are very important.
The first benefit of design patterns is that they simplify communication between software developers. They can promptly describe how a bit of code which uses that pattern works. The alternative is to fully describe the solution which is time-consuming and error-prone.
Secondly, they are off-the-shelf solution-forms for common problem-forms. If you know your patterns and encounter a problem where you need to find a good way to get information from possibly multiple producer objects to multiple consumer objects without introducing unnecessary coupling between classes.
And the last benefit is Universal programmers’ vocabulary. You simply pronounce the name of a pattern instead of spending an hour explaining to other programmers the benefits of your new design and listing the required classes.
These benefits boost the result. You are able to quickly solve certain issues with their help, and when the task is completed, the solution to a problem can easily be discussed.
Just imagine that there are no design patterns anymore. So you have an issue, which is not a common design problem, and it appears to be time-consuming for you to come up with a great solution. It will be more or less like a suitable pattern. After that, you will have to review the solution with your colleagues, which also will take a lot of time.
This is all related to a warning that should be obvious. Don’t try to move issues into patterns that don’t match. If the pattern doesn’t match the issue, then the answer will arrive finally being complicated and obviously planned or forced, and you will lose the effort reduction advantage of patterns. What is more, since your work cannot match along with your colleagues’ understanding of the pattern’s meaning, you won’t have the advantage of communication. Actually, you will likely increase the cost of communication beyond the no-patterns cost because the misuse of the pattern will give your co-worker a false understanding of the solution which is worse than no understanding at all.
Java Design Patterns are divided into three categories: creational, structural, and behavioral design patterns.
Creational design patterns are all about class instantiation or object creation. These patterns can be further categorized into Class-creational patterns and object-creational patterns.
Structural design patterns are responsible for building simple and efficient class hierarchies and relations between different classes.
Behavioral patterns are about identifying common communication patterns between objects and realize these patterns.
Let’s consider the Proxy pattern
Proxy pattern is determined to “Provide a surrogate or placeholder for another object to control access to it”.
The Proxy pattern is one of the most important design patterns because it provides an alternative to extending functionality with inheritance. That alternative is object composition, where an object (proxy) forwards method calls to an enclosed object (real subject).
Proxy is a structural design pattern which allows you to add a substitute for another object to control access to it, which may be remote, expensive to create or in need of being secured.
Why do you need to control the access to an object? Let’s imagine you have got an effective object which uses up lots of system resources. Sometimes you require it, but not regularly.
So, the object might be created when it is actually required, and not at the stage of program start. Each client of this object would have to get some sort of deferred initialization code. It definitely leads to a vast amount of overlapping.
The Proxy pattern offers a substitute class that has the same interface as an original service object. Upon receiving the request from a client, the proxy object builds an instance of a service object and delegate it all real work.
Now, what good is it to have that? It is possible to set some code into a proxy object that would be executed just before (or after) requiring the same method in a real service object. The proxy pattern shares the same interface with the service object, so it could be transferred to any code that recognizes service objects.
A cheque is a written document, directing a bank to pay a specific amount of money. Both cheque and cash have a shared interface: they can be used as payment. However, a cheque is a proxy for a group of cash.
For the buyer the benefit is that it is not necessary to carry a ton of cash, and the shop owner can convert a cheque into money, referring to the bank.
Here is the structure of the Proxy Pattern and its important participants.
- 1. Provides 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.
- Maintains an interface the same as Subject’s so that a proxy can be substituted for the real subject.
- Manages access to the real subject and may be in charge of creating and deleting it.
Determines the shared interface for RealSubject and Proxy so that a Proxy can be used anywhere a RealSubject is awaited.
Determines the real object that the proxy suggests.
Proxy is useful when you need more adaptable or complex reference to an object than just a simple pointer. You may use the Proxy pattern in the following cases:
Virtual proxy – when you have a heavyweight object that loads data from a file system, network or database. Instead of loading data at the application start, one could delay the object’s initialization to a time when it is needed. A virtual proxy creates expensive objects on demand
Protection proxy controls access to the original object. It is useful when objects should have different access rights and you want to protect an object from unauthorized usage. For instance, when objects are crucial parts of an operating system and programs (including malicious ones) are their clients. Proxy can check the client’s credentials on each request and pass the request to the service object only if the access is granted.
Remote proxy provides a local representative for an object in a different address space. When a real service object is located on a remote server. In this case proxy passes client request to a remote service object over the network, handling all the network transfer details.
- Define an interface that would make the alternate and the original object interchangeable.
- Create a substitute class. It should contain a link to the service object. Most often, the service object is created by proxy. In rare cases, proxy receives a ready-made service object from the client through the constructor.
- Carry out the proxy methods depending on its purpose. More often, having done some useful work, the proxy has to pass the request to the service object.
- Consider introducing a factory that would decide which of the objects to create – a proxy or a real service object. However, this logic can be placed in the creating method of the proxy itself.
- Consider whether you can implement a virtual proxy when the client first accesses the heavyweight objects.
Advantages and Disadvantages
- Allows you to control the service object imperceptibly for the client.
- May work even if the service object has not been created yet.
- Monitors the life cycle of the service object, even when clients do not care.
- Complicates program code due to the introduction of additional classes.
- Increases response time from the service.
Other Patterns Connection
- Proxy provides the same interface. Adapter provides a different interface to its subject. Decorator provides an advanced interface.
- Facade is similar to Proxy in that it replaces a complex subsystem and can initialize it itself. But unlike the Facade, the Proxy has the same interface as his service object, so that they can be interchanged.
- Decorator and Proxy have similar structures, but different purposes. They are similar in that both are built on composition and delegate work to other objects. Patterns are different in that Proxy governs the life of the service object, whereas Decorator structure is controlled by the client.
Dynamic proxies are a powerful and underused tool in implementing many design patterns, including the Proxy, Decorator, and Adapter. Proxy-based implementations of these templates are easy to write, they are harder to make mistakes, and they are more versatile; in many cases, a single dynamic proxy class can serve as a decorator or proxy for all interfaces, rather than writing a static class for each interface. For all applications, except for the most critical in terms of performance, dynamic proxy technology may be preferable to writing code manually or using the technology generated stubs.
Let’s say we have a big class with a bunch of methods in which we want to perform the same action — for example, logging, audit trail, security, serialization of results. In classical OOP, this problem is solved either by copy-paste or by selecting each method into a separate class, which is also not convenient. And at this very moment magic called reflection proxy comes to the rescue. It is enough to select the class methods in the interface to create a wrapper that will perform actions that are the same for all methods (before or after the logic of the method itself).
Roman Taluyev – Software Developer
Natalia Alexandrova – Technical Writer