Design patterns, made famous by the "gang of four" (GOF), as they are fondly called (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides), are a collection of proven steps to be followed for a particular type of problem in software scenario. Java Design patterns provide a time tested solution which can be applied to a set of problems (the problems will have a common set of characteristics) to come to a solution. Obviously, the solution should be optimal in terms of execution.
Among the different categories of Java Design Patterns available, this article will focus on "Creational Design Patterns", which focus on the creation of objects in Java from a class or group of classes. The patterns present under the umbrella of Creational Design Patterns basically define:
- How the Objects will be instantiated
- How many Objects will be instantiated
- At what point the Objects will be instantiated
Creational design patterns contain the following design patterns:
- Factory Method Pattern
- Abstract Factory Pattern
- Singleton Pattern
- Builder Pattern
- Prototype Pattern
This article covers each of these patterns, includes examples that show how to implement the patterns, and describes under which circumstances each of the patterns can be applied.
Factory Method Design Pattern
The factory method pattern is used when we have group of classes and one class needs to be instantiated to represent the user data. Which class to instantiate depends upon the user data. So, basically we have a class factory, and an object will be the product.
Which class's object will come out of the factory is abstracted from the user, as to the user it's just the information that is contained in the object that is shown.
There is a class, which contains a method which will take the user data and create an object of one of the class out of group of classes. This class is called the Factory Class and hence the name'Factory Method Design Pattern'.
Let us elaborate this with an example. Consider the scenario where we have an abstract
Account class which has three subclasses that extend it, namely:
Figure 1 is the Class Diagram for the
The three subclasses that extend this class provide the definition of the methods.
OpenAccount is a factory class which has a method for creating an object of one of the subclasses, depending upon the value of attribute
type that is provided by the user. The created object is then returned back to the user.
Listing 1 is the source code for this Factory class scenario.
Instances when you should consider using the Factory Method pattern include:
- when the object creation depends upon the user data or some event;
- when which object is getting created is abstracted from the user;
- when the type of object created is to be decided at runtime.
Abstract Factory Design Pattern
This pattern is used when we have an object to be returned out of group of objects. The group of objects belong to the same theme. This returned object acts like a factory, which therefore returns another object to the user.
The pattern has an interface, which is implemented by different classes to form the group of objects all coming from the same interface. There is one product class whose object is to be created in the end.
The group of classes created each contain different methods, each returning an object of type
Product. We'll explain this with an example. Suppose we are writing a program related to investments such as stocks, bonds, and derivatives. In this example the product is
Amount. So, let's create an Abstract Class
Amount class is extended by three more classes namely:
Principal. We have an interface
Investment which is implemented by three classes, namely:
The class diagram of for the product
Amount and abstract class
Investment is shown in Figure 2.
The source code for the Abstract Factory class is provided in Listing 2.
Thus, abstract factories first return an object out of group of objects, then this object further returns an object out of a set of possibilies, depending upon the user's input. Another way of saying this: the Abstract Factory pattern encapsulates a group of factories, each object out of which itself acts as in independent factory.
Consider using the Abstract Factory method in the following situations:
- when a lot of subclasses are supposed to be added at runtime or later in the application;
- when one type of object encapsulates other type of object;
- when the System should work with the product without being aware of the specific classes interfacing with the product.
Singleton Design Pattern
The Singleton Design Pattern restricts number of occurrences of an object of a class to one. When we want only one object of a particular class to be created and used by all in the other modules so that the concurrency of the data held by the object is maintained, we use the Singleton Pattern. Here are steps to be followed to implement the Singleton Design Pattern:
- Declare a class and declare a static member variable of type
- Make the constructor private.
- Create a method which will instantiate the static member variable if it is null otherwise return the old created object.
Consider a logging function that used to log the statements in a large enterprise application. We want to have only one logger for the entire application and share it across the whole code. Below is the implementation of this scenario.
Let's create a class
Logger on which we will apply the singleton pattern. Figure 3 presents the class diagram.
Listing 3 is the code to be implemented.
Builder Design Pattern
This pattern is used to create object by combining a group of objects together internally. The pattern assembles a number of objects depending upon the user input and brings out a complex objects. The Builder Pattern is different from Abstract Pattern as it brings out a complex object while the later gives a factory returning a simple object. Figure 4 makes things little clearer.
We have three components classes
C. There is a builder class which will take the user input and based on that input will roll out a complex objects containing the component objects in a defined manner.
Let's consider an example that isn't from the software engineering field. We go to a restaurant and order for a milk shake. There can be many types of shakes available. The cook here acts as the builder. Depending upon our input he/she takes different components, namely ice, milk, fruit or ice cream, etc., and comes back with a complex object
Shake which is different for different inputs from the user.
Taking another example from software engineering: consider a scenario where we have to make a Web interface that differs depending upon the user. The different components of the webpage will be:
- Managers Dashboard
- Forum column
- Common Display area
When the manager logs into the system, and we have to show the Web interface for the manager. So we have builder class which will take following components and make the UI:
Header, Footer, Gallery, Manager's Dashboard.
Similarly, for other types of users we can have different combinations of the possible components displayed, giving each type of user a customized UI.
Consider using the Builder Design Pattern in the following situations:
- when a complex object has to be made and the implementation has to be hidden from the user;
- when we want to add more subclasses to our system without the user's knowledge.
Prototype Design Pattern
The Prototype Design Pattern is used when we have an object of a particular class already available, and creation of a new object is a costly affair in terms of memory, resources, and operations involved. We simply clone the object that's already available, to get an exact replica of the object; then we work on the cloned object to get the required result. To make this possible, the class must implement the 'Cloneable interface'.
Consider a scenario where we have sent a query to Database to extract information on all the employees. Now the user wants to see the information on all the managers in the organization. Instead of sending a new query to the database for managers, we clone the existing object containing the information on all the employees, and filter the data set so only the manager details will be displayed to the user.
The concept of cloning is demonstrated in email client UIs, where we sort the emails on different criteria. Listing 4 presents an example of the code to be implemented.
The code shows that the first time the object is created, and the next time we call the
clone method we get the same object back with same data contained in it. We modify the data (by appending "Second Object") to it and display it to the user.
Consider using the Prototype Pattern in the following situations:
- when the user interface is not to be changed; for example, a dropdown remains a dropdown, or a Radio Button remains a Radio Button, no matter what data has to be displayed;
- when creating a new object is a costly affair;
- when the data to be displayed is already present in some other object.
Conclusion: Design Patterns Application Decisions
Most of the time in the software engineering scenario, it is beneficial to use more than one design pattern for a situation, as that typically yields a momre optimal result. Hence the patterns discussed here can be applied to multiple problems and situations, and it is left up to the application designer or architect to decide which specific patterns to apply and where to apply them.