Java Design Patterns
Design patterns are a collection of patterns that are seen to occur over and over again in the software industry. So classifying this recurrent behavior is helpful to programmers because by studying them, then can become aware of the common problems and issues that occur often in their work. Also, by referring to a design pattern by name, conveys a lot more information to other fellow programmers as compared to explaining the whole algorithm.
Singleton pattern is followed when only one instance of the class is required.
To do this, following is done:
Factory method is used to create complex objects in such a way that implementation details of creation are hidden from the clients and the clients access the created object only by an interface.
Builder pattern is used when the client provides several parameters to the builder class for building a complex object. This is very similar to the Factory method but the difference lies in the level of customization. Builder pattern implementations have much greater degree of customization in the sense that builder objects typically take many more values than the Factory pattern objects.
Prototype pattern is used when its easier to clone than to create.
For example, if same database objects are required in a number of functions, then reading them from the database again and again will reduce performance. Cloning in this case would be much faster.
So the use of cloning technique to avoid a costly creation is called prototype.
Reuses and shares objects that are costly to create.
Example: ThreadPoolExecutors create a pool of threads and those threads never die. They just wait for the next task to arrive. When the task arrives, some of the threads complete it and then go into wait state again. This kind of a pool avoids the overhead of thread creation every time a new task comes.
Iterator pattern allows to traverse a collection without exposing the internal implementation of the collection. Typically, an iterator has 2 methdos - hasNext() and next() which help its clients to iterate without caring whether the internal representation of the collection is an array, list, tree, map or some other complex type.
Observer pattern is used when there are many listeners for change in an object’s state. Each listener implements the observer pattern by registering a method with the observable. When the observable object changes state, it notifies all the observers by calling their respective handlers.
To optimise this, the notification agent can be made into a separate thread which collates the notification requests from the observable and notifies when it seems appropriate for example, when x number of requests have come from the observer. This reduces the load on the observable as it does not have to wait for all the observers to complete their processing. Plus the notification of observers can be optimized by not calling them too frequently.
Observer - Observable classes
These two classes help to implement observer pattern in Java.
Observable class has methods like:
The above help observer to manage and notify observers.
Observer interface has one method:
This method is called whenever the Observer calls notifyObservers().
Note: NotifyObservers() calls update() sequentially i.e until one Observer.update() has completed, other Observers cannot have their update() called. Also, Observable itself is blocked. So, it’s always a best practice to make multi-threaded applications in such cases to allow proper execution. Also, since the oObservable would most likely be a front end of the application, it makes sense to have it least loaded and kept free for listening to incoming requests.
If there are multiple Observable objects sharing Observers, then massive synchronization would be needed.
CoR is used when the exact handler of a request is not known but the path on which it can be consumed is known well. A very good example of this is a GUI application where widgets listen to different types of events. Some widgets consume keyboard events and some consume mouse events. When the event is generated in a parent field, the event is passed along to the child objects (not all children get the event off-course, because the x,y coordinates direct a clear path for the event to filter down).
So in the above case, the widgets form a chain of responsibility.
Another example could be the filters present in web applications. Each filter does some processing and then passes on the request to the next filter until it reaches the servlet.
However, care must be taken to have the chain complete at all times, else there is a risk of losing some of the events.
Command pattern is useful when an object contains a parameterized command like a Macro (Vim users can think of this like the . operator which repeats the previous command on the current cursor). The command has provision to be parameterized by the client. Roughly speaking, even a function can be thought of as a command object parameterized by its arguments.
However, from a design pattern viewpoint, a command pattern is exercised when the command is inside an object which is parameterized by its setter method or the constructor.
Command objects can be put in a queue such that they can be cancelled if not yet executed.
Mediator patterns provides a stage for the participating objects to play so that the participating objects can remain loosely coupled with each other. A good example is the layout managers in GUI applications. Layout patterns allow each child to remain loosely coupled with the position of other objects in the UI. Even if a new object is added to UI or an old one removed, all the other objects need not explicitly change their position to keep the system usable. The mediator layout pattern accommodates the changes for its children so that they can focus on their core competencies.
Strategy pattern is useful when a bunch of algorithms need to be applied interchangeably on an object. For example: consider the insurance policies of people. Some like to have the aggressive insurance plan linked more to equities and lesser to debts while other ones want the opposite and still others want to have it custom made. All these variations represent the algorithms which are applied to the policy of a person after some time depending upon the needs of the customer.
Visitor pattern is somewhat similar to the Iterator pattern as it allows a heterogeneous collection of objects to be iterated by a visitor. Consider a group of records each with different type. If a visitor wants to access most of these records, then it would be messy to check the type of each object and then take corresponding action. Instead, the visitor pattern demands that the heterogeneous objects implement an interface containing some method (say ‘visit’)) which will be called by the visitor during its visit. In that method, the visitor’s handler should be called. Off course the handler of the visitor should be overloaded with all the types of objects it intends to handle. If some objects do not wish to be handled, they can leave their accept method empty.
Difference between Iterator and Visitor pattern is that Iterators typically operate on the same kind of objects while Vistor patterns do not. Secondly an iterator makes the collection objects available for use by clients while a Visitor is the client itself visiting the collection objects.
Null object pattern is used to handle an unhandled case in a collection of types.
Having a null object ensures that the unhandled case is handled gracefully and every client of the system need not handle that case individually.
It also comes handy in cases when the actual handler is not yet ready to use.
For example, an application may produce some widgets for display on the UI and those widgets can crowd the queue if they are not consumed within a given time frame. A null object pattern can come in handy here till the actual consumer of the widgets is ready for operation.
Another use is when the functionality needs to be removed temporarily without affecting the system in multiple points. For example, if logging for a class needs to be removed, then logger for that class could be replaced by a null pattern logger (one that does nothing) instead of removing the log commands everywhere in the class.
Adapter helps 2 classes work together by making their interfaces compatible. For example, if two third party classes are there. One class produces an integer while another one consumes string representation of an integer, then the adapter between these two classes would convert the integer to string and enable the 2 classes to communicate.
Proxy pattern is used mostly when we use a wrapper object. By using a wrapper object, we can control the functionality exposed by the wrapped object. For example: to make a class read-only, it can be wrapped in another objects which throws exception in all the write methods but delegates the read methods to the original class.
Proxy pattern is used to eliminate the unwanted or costly methods from a class.
Decorator pattern is used to add functionality to an existing class such that
every decorator class can keep on adding more functionality and need not be aware of
functionalities added by other decorators. For example: consider a collection class MyCollection which
adds String objects to a list. A decorator pattern class for this can be a class which wraps this object
into another object, implements similar methods which delegate the functionality to the underlying object, but over-rides the
add method in such a way that it converts all null objects into an empty string. Thus our decorator class has added
functionality by wrapping this object. Another decorator can similarly process each string by prepending some other string.
Yet another decorator can append something to each input string and so on.
Template method pattern can very roughly be described as that of inheritance. When a derived class inherits a base class, it inherits the functionality from base class as a template. Every base-class, derived-class cannot be said to have Template method pattern. TMP comes into play when the base class keeps the overall algorithm unchangeable. It only allows the derived classes to add some variation to the algorithm execution, but does not allow the base classes to mess with the overall algorithm. If derived classes are allowed to do so, then it is not Template Method pattern.
|Email:||(Your email is not shared with anybody)|