A Creational design pattern is concerned about the process of object creation in Java from one or more classes. On the basis of a static and dynamic instantiation process, a creational pattern is clubbed into a class creational pattern and object creational pattern respectively. A class creational pattern uses inheritance as the mechanism of object instantiation; on the other hand, an object creational pattern delegates an object to create at run time. It addresses the issue of what objects are instantiated and in what manner.
The Group
The Creational patterns concept is an umbrella of five design patterns, namely,
- Factory Method Pattern
- Abstract Factory Pattern
- Builder Pattern
- Singleton Pattern
- Prototype Pattern
Each pattern will be discussed in detail in this article.
Factory Method Pattern
This is the only class pattern under the Factory Method. User input decides which class to instantiate. When there are many subclass derived from a super class, the factory method pattern ensures that the specific subclass object is returned according to the user’s choice.
public class Employee { private String name; private String type; private String payment; //getters, setters and toString() }
Listing 1: Structure of the parent class
public class PermanentEmployee extends Employee{ public PermanentEmployee(String name){ setName(name); setType("Permanent"); setPayment("Monthly"); } }
Listing 2: Subclass of Employee with its relevant information
public class ContractualEmployee extends Employee{ public ContractualEmployee(String name){ setName(name); setType("Contractual"); setPayment("Hourly"); } }
Listing 3: Subclass of Employee with its relevant information
public class EmployeeFactory { public Employee createEmployee(String name, String type){ if(type.equals("permanent")) return new PermanentEmployee(name); else if(type.equals("contractual")) return new ContractualEmployee(name); else return null; } }
Listing 4: Factory class that instantiates a relevant employee object
public class TestFactoryPattern { public static void main(String[] args) { EmployeeFactory factory=new EmployeeFactory(); System.out.println(factory.createEmployee("Andrew", "permanent").toString()); //... System.out.println(factory.createEmployee("Joseph", "contractual").toString()); } }
Listing 5: Testing the factory method pattern
Abstract Factory Pattern
The Abstract Factory Pattern is sommewhat similar to the factory method, but the difference is that the super class is abstract (cannot be instantiated directly) and it returns a factory object rather than returning an object of a specific class. This factory object can be used later to create objects at run time according to user choice.
public abstract class Employee { private String name; public abstract float getSalary(); //...getters and setters }
Listing 6: Structure of the abstract parent class
public class SalariedEmployee extends Employee{ private float basic; private float allowance; public SalariedEmployee(String name, float basic, float allowance){ //... } //...getters and setters @Override public float getSalary() { return (getBasic()+(getBasic()*getAllowance())); } }
Listing 7: Structure of the inherited subclass
public class CommissionedEmployee extends Employee{ private float salesAmount; private float commission; public CommissionedEmployee(String name, float sales, float commission){ //... } //...getters and setters @Override public float getSalary() { return (getSalesAmount()*getCommission()); } }
Listing 8: Structure of the inherited subclass
public class EmployeeFactory { public Employee createEmployee(String name, String type, float bs, float ac){ if(type.equals("sal")) return new SalariedEmployee(name,bs,ac); else if(type.equals("comm")) return new CommissionedEmployee(name, bs, ac); else return null; } }
Listing 9: The Factory class helps in creating objects according to the parameter passed
public class TestAbstractFactoryPattern { public static void main(String[] args) { EmployeeFactory factory=new EmployeeFactory(); Employee e1=factory.createEmployee("Andrew", "sal",5000.0f,6.7f); //... Employee e5=factory.createEmployee("Joe","comm",360000.0f,0.18f); System.out.println(e1.getName()+" received: $"+e1.getSalary()); //... System.out.println(e5.getName()+" received: $"+e5.getSalary()); } }
Listing 10: Test class for abstract factory pattern
Singleton Pattern
The Singleton pattern ensures that only one instance of a particular class is created per application. This pattern is useful where only one object instance is required, for example, while connecting to a database using only one object that manages the connection. Too many database connection objects are not only difficult to maintain, but also are adverse to performance.
public final class MySingleton { private static final MySingleton singleton=new MySingleton(); private MySingleton(){ System.out.println("object created..."); } public static MySingleton getInstance(){ return singleton; } }
Listing 11: Singleton class
public class TestSingletonPattern { public static void main(String[] args) { MySingleton s1=MySingleton.getInstance(); MySingleton s2=MySingleton.getInstance(); } }
Listing 12: Test class for singleton pattern
Builder Pattern
The Builder Pattern simplifies creating a complex object in a one step at a time manner. It helps in separating the instantiation process of a complex object from its representation. This pattern is particularly useful in creating objects of the type given in Listing 13.
public class Address { private final String houseNumber; private final String floorNumber; private final String street; private final String city; private final String province; private final String country; private final String zip; private final String landmark; private Address(AddressBuilder ab){ this.houseNumber=ab.houseNumber; this.floorNumber=ab.floorNumber; this.street=ab.street; this.city=ab.city; this.province=ab.province; this.country=ab.country; this.zip=ab.zip; this.landmark=ab.landmark; } public static class AddressBuilder{ private String houseNumber; private String floorNumber; private String street; private String city; private String province; private String country; private String zip; private String landmark; public AddressBuilder houseNumber(String hno){this.houseNumber=hno; return this;} public AddressBuilder floorNumber(String fno){this.floorNumber=fno; return this;} public AddressBuilder street(String st){this.street=st; return this;} public AddressBuilder city(String ct){this.city=ct; return this;} public AddressBuilder province(String p){this.province=p; return this;} public AddressBuilder country(String c){this.country=c; return this;} public AddressBuilder zip(String z){this.zip=z; return this;} public AddressBuilder landmark(String l){this.landmark=l; return this;} public Address build(){ return new Address(this); } } //... toString() } }
Listing 13: The Builder pattern is used to create complex Address objects
public class TestBuilderPattern { public static void main(String[] args) { Address a = new Address.AddressBuilder().houseNumber("HNO-22/34") .floorNumber("First Floor").street("123 ABC Street") .city("Some City").province("Some Province") .country("Some Country").zip("12345676") .landmark("Near XYZ beach").build(); System.out.println(a); } }
Listing 14: Testing the Builder Pattern
Prototype Pattern
The Prototype design pattern is used when we need a shallow copy of an object. Creating a new object is expensive in terms of memory and resources, so what we can do is make a clone of the object already available. Sometimes an exact replica of an object serves our purpose rather than creating a new object afresh. In Java, we can achieve this with the help of a Cloneable interface.
public class Box implements Cloneable{ private String color; public Box(String col){ setColor(col); } public Box clone(){ Box b=null; try{ b=(Box)super.clone(); }catch(Exception e){ } return b; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } }
Listing 15: The Box class implements the Cloneable interface
public class TestPrototypePattern { public static void main(String[] args) { Box box1=new Box("GREEN"); Box box2=box1.clone(); System.out.println("BOX 1: "+box1.getColor()); System.out.println("BOX 2: "+box2.getColor()); box2.setColor("BLUE"); System.out.println("BOX 2: "+box2.getColor()); } }
Listing 16: Testing Prototype Pattern
Conclusion
The Creational Pattern mainly focuses on object instantiation. There are certain overlapping circumstances where it may be difficult to choose an appropriate pattern. For example, the design decision between the Factory method pattern or Abstract factory pattern can be confusing at times. However, in some cases we can precisely decide which pattern better serves our purpose. A better understanding of the patterns can shed a lot of load from the shoulders of a code designer. These patterns evolved from programmers’ toil and can make life easy once one gets a good grasp of the concept behind them.