You are here
Home > Design >

Creational Design Patterns In Java

Creational Design Patterns in JavaAs the first part of Design Patterns in Java, we will discuss about Creational Design Patterns in Java in this article. We have already covered the Introduction of Design Patterns in Java in a separate article. In the introductory part, we have already discussed about What, Why & advantages of Design Patterns. We will discuss five design patterns in total in this article that come under the category of Creational Design Patterns.

Creational design patterns deal with providing solutions to instantiate an object in the best possible way for specific situations. Let’s start with our topic ‘Creational Design Patterns in Java’ and other concepts related to it.

What are Creational Design Patterns in Java?

Creational design patterns provide solution to instantiate an object in the best possible way for specific situations.

What are the types of Creational Design Patterns in Java?

Generally, there are five well-known types of Creational Design Patterns in Java.

  1. Singleton Pattern
  2. Factory Pattern
  3. Abstract Factory Pattern
  4. Builder Pattern
  5. Prototype Pattern

Creational Design Patterns in Java

Now, let’s understand each Design Pattern one by one.

Singleton Design Pattern

From the definition, it seems to be a very simple design pattern but when it comes to implementation, it creates a lot of implementation concerns. Also, the implementation of Java Singleton pattern has always been a controversial topic among developers. Therefore, we have explained it in a separate article ‘Singleton Design Pattern In Java With All Scenarios‘. In that article, you will learn about Singleton Design Pattern in Java with all Scenarios, different ways to implement Singleton design pattern and some of the best practices for its usage.

Factory Design Pattern

The Factory design pattern is used when we have a super class with multiple sub-classes and based on input, we need to return one of the sub-classes. This pattern takes out the responsibility of instantiation of a class from a client program to the factory class. Moreover, we can apply Singleton pattern also on Factory class or make the factory method static.

Super class in factory pattern can either be an interface, or an abstract class, or a normal Java class.

Example 

For example, let’s assume we are creating objects from a factory of Mobiles.

IMobile.java

public interface IMobile {

      public void cost();
      public void pictureCapacity();
      public void batteryPower();
}

Lenovo.java

public class Lenovo implements IMobile {

      @Override
      public void cost() {
         System.out.println("Lenovo Cost starts from 10000");
      }

      @Override 
      public void pictureCapacity() {
         System.out.println("Lenovo camera capacity starts from 10 MP");
      }

      @Override
      public void batteryPower() {
         System.out.println("Lenovo battery power starts from 2500 MAh");
      }
}

Samsung.java

public class Samsung implements IMobile {

      @Override
      public void cost() {
         System.out.println("Samsung Cost starts from 6000");
      }

      @Override
      public void pictureCapacity() {
         System.out.println("Samsung camera capacity starts from 4 MP");
      }

      @Override
      public void batteryPower() {
         System.out.println("Samsung battery power starts from 1200 MAh");
      }
}

MobileFactory.java

public class MobileFactory {

      public MobileFactory(){

      }

      IMobile createMobile(String type){

         IMobile mob=null;
         if("len".equalsIgnoreCase(type)){
            mob=new Lenovo();
            System.out.println("Lenovo created");
         }else if("sam".equalsIgnoreCase(type)){
            mob=new Samsung();
            System.out.println("Samsung created");
         }
         return mob;
      }
}

FactoryTest.java

public class FactoryTest {

      public static void main(String[] args) {
         MobileFactory factory= new MobileFactory();

         Lenovo len = (Lenovo)factory.createMobile("len");
         len.batteryPower();

         Samsung sam= (Samsung)factory.createMobile("sam");
         sam.cost();
      }
}

Output

Lenovo created
Lenovo battery power starts from 2500 MAh
Samsung created
Samsung Cost starts from 6000

Benefits

  1. Factory pattern offers an approach to code for interface rather than implementation.
  2. Factory pattern removes the instantiation of actual implementation classes from client code, making it more robust, less coupled and easy to extend. For example, we can easily change class implementation because client program is unaware of it.
  3. Factory pattern also provides abstraction between implementation and client classes through inheritance.

Usage in JDK

  1. util.Calendar, ResourceBundle and NumberFormat getInstance() methods use Factory pattern.
  2. valueOf() method in wrapper classes like Boolean, Integer etc.

 


Abstract Factory Pattern

Almost similar to Factory Pattern, except the fact that it’s more like factory of factories. If you are familiar with factory design pattern in java, you will notice that we have a single Factory class that returns the different sub-classes based on the input provided. Generally,  factory class uses if-else or switch-case statement to achieve this. However, in Abstract Factory pattern, we get rid of if-else block and have a factory class for each sub-class and then an Abstract Factory class that will return the sub-class, based on the input factory class.

In fact, An abstract factory is a factory that returns factories. Why is this layer of abstraction useful? A normal factory can be used to create sets of related objects. An abstract factory returns factories. Hence, an abstract factory is used to return factories that can be used to create sets of related objects.

For example, you could have a Honda factory that returns car objects (Brio, Civic, etc.) associated with a Honda factory. You could also have a Hyundai factory that returns car objects (Santro, EON) associated with a Hyundai factory. However, we could create an abstract factory that returns these different types of car factories depending on the car that we were interested in. Furthermore, we could then obtain car objects from the car factories. Via polymorphism, we can use a common interface to get the different factories, and we could then use a common interface to get the different cars.

Example

For example, let’s assume the previous example of Mobiles. However, this time we will create the objects using one extra layer of abstraction.

IMobileFactory.java

public interface IMobileFactory {

       IMobileFactory createMobile(String type);
}

MobileFactory.java

public class MobileFactory implements IMobileFactory {

     @Override  
     public IMobileFactory createMobile(String type) {

        IMobileFactory mob = null;
        if ("lenf".equalsIgnoreCase(type)){
            mob= new LenovoMobileFactory();
        } else if ("samf".equalsIgnoreCase(type)){
            mob= new SamsungMobileFactory();
        }
        return mob;
     } 
}

LenovoMobileFactory.java

public class LenovoMobileFactory extends MobileFactory {

      Lenovo createLenovoMobile(){
        return new Lenovo();
      }
}

SamsungMobileFactory.java

public class SamsungMobileFactory extends MobileFactory {

      Samsung createSamsungMobile(){
         return new Samsung();
      }
}

AbstractFactoryTest.java 

public class AbstractFactoryTest {

      public static void main(String[] args) {
         MobileFactory factory= new MobileFactory();
         LenovoMobileFactory lmf= (LenovoMobileFactory)factory.createMobile("lenf");
         Lenovo ln= (Lenovo)lmf.createLenovoMobile();
         ln.pictureCapacity();
      }
}

Output

Lenovo camera capacity starts from 10 MP

Benefits

  • Abstract Factory pattern also offers an approach to code for interface rather than implementation.
  • Abstract Factory pattern is “factory of factories” and can be easily extended to accommodate more products. For example, we can add another sub-class ‘Dell’ and a factory ‘LaptopFactory’.
  • Abstract Factory pattern is robust and it eliminates conditional logic unlike Factory pattern.

Usage in JDK

  • xml.parsers.DocumentBuilderFactory#newInstance()
  • xml.transform.TransformerFactory#newInstance()
  • xml.xpath.XPathFactory#newInstance()

When to use

When a family of related objects is designed to be used together, and you need to enforce this constraint.

 


Builder Design Pattern

In general, the details of object construction, such as instantiating and initializing the components that make up the object, are kept within the object, often as part of its constructor. This type of design closely ties the object construction process with the components that make up the object. However, this approach is suitable as long as the object under construction is simple and the object construction process is definite and always produces the same representation of the object.

Moreover, this design may not be effective when the object being created is complex and the series of steps constituting the object creation process can be implemented in different ways. Thus, producing different representations of the object. Because the different implementations of the construction process are all kept within the object, the object can become bulky (construction bloat) and less modular. Subsequently, adding a new implementation or making changes to an existing implementation requires changes to the existing code.

The intent of the Builder Pattern is to separate the construction of a complex object from its representation, so that the same construction process can create different representations. This type of separation reduces the object size. The design turns out to be more modular with each implementation contained in a different builder object. Therefore, Adding a new implementation (i.e., adding a new builder) becomes easier. Furthermore, the object construction process becomes independent of the components that make up the object. This provides more control over the object construction process.

Builder

It specifies an abstract interface for creating parts of a Product object. The Builder Pattern suggests moving the construction logic out of the object class to a separate class referred to as a builder class. However, there can be more than one such builder classes, each with different implementations for the series of steps to construct the object. Moreover, each builder implementation results in a different representation of the object.

ConcreteBuilder

  • Constructs and assembles parts of the product by implementing the Builder interface.
  • Defines and keeps track of the representation it creates.
  • Provides an interface for retrieving the product.

Director

It constructs an object using the Builder interface. The Builder pattern suggests using a dedicated object referred to as a Director, which is responsible for invoking different builder methods required for the construction of the final object. Moreover, different client objects can make use of the Director object to create the required object. Once the object is constructed, the client object can directly request from the builder the fully constructed object. In order to facilitate this process, a new method getObject () can be declared in the common Builder interface to be implemented by different concrete builders.

Product

  • Represents the complex object under construction. Further, ConcreteBuilder builds the product’s internal representation and defines the process by which it’s assembled.
  • Includes classes that define the constituent parts, including interfaces for assembling the parts into the final result.

Example

For example, let’s assume an example of building a meal as below:

MealBuilder.java 

public interface MealBuilder {

      public void buildStarter();
      public void buildMainCourse();
      public void buildDesserts();

      public Meal getMeal();
}

Meal.java 

public class Meal {

     private String starter;
     private String mainCourse;
     private String desserts;

     public String getStarter() {
        return starter;
     }
     public void setStarter(String starter) {
        this.starter = starter;
     }
     public String getMainCourse() {
        return mainCourse;
     }
     public void setMainCourse(String mainCourse) {
        this.mainCourse = mainCourse;
     }
     public String getDesserts() {
        return desserts;
     }
     public void setDesserts(String desserts) {
        this.desserts = desserts;
     }
     @Override
     public String toString() {
        return "Meal [starter=" + starter + ", mainCourse=" + mainCourse
          + ", desserts=" + desserts + "]";
     }
}

IndianMealBuilder.java

public class IndianMealBuilder implements MealBuilder {

      Meal meal;

      public IndianMealBuilder(){
         meal= new Meal();
      }

      @Override
      public void buildStarter() {
         meal.setStarter("Indian Starter");
      }

      @Override
      public void buildMainCourse() {
         meal.setMainCourse("Indian MainCourse");
      }

      @Override
      public void buildDesserts() {
         meal.setDesserts("Indian Desserts");
      }

      @Override
      public Meal getMeal() {
         return meal;
      }
}

JapaneseMealBuilder.java

public class JapaneseMealBuilder implements MealBuilder {

      Meal meal;

      public JapaneseMealBuilder() {
         meal= new Meal();
      }

      @Override
      public void buildStarter() {
         meal.setStarter("Japanese Starter");
      }

      @Override
      public void buildMainCourse() {
         meal.setMainCourse("Japanese Main Course");
      }

      @Override
      public void buildDesserts() {
         meal.setDesserts("Japanese Dessert");
      }

      @Override
      public Meal getMeal() {
         return meal;
      }
}

MealDirector.java

public class MealDirector {

       private MealBuilder mealBuilder = null;

       public MealDirector(MealBuilder mealBuilder) {
          this.mealBuilder = mealBuilder;
       }

       public void constructMeal() {
          mealBuilder.buildStarter();
          mealBuilder.buildMainCourse();
          mealBuilder.buildDesserts();
       }

       public Meal getMeal(){
          return mealBuilder.getMeal();
       }
}

BuilderTest.java

public class BuilderTest {

      public static void main(String[] args) {

         MealBuilder indianMealBuilder = new IndianMealBuilder();
         MealDirector mealDirector= new MealDirector(indianMealBuilder);
         mealDirector.constructMeal();
         Meal meal= mealDirector.getMeal();
         System.out.println("Requested meal is :" +meal);
      }
}

Output

Requested meal is :Meal [starter=Indian Starter, mainCourse=Indian MainCourse, desserts=Indian Desserts]

Another form/version of the Builder Pattern

Sometimes, there is an object with a long list of properties. Most of these properties are optional. For example, let’s consider an online form which needs to be filled in order to become a member of a website. You need to fill all the mandatory fields but you can skip the optional fields. Even sometimes it may look valuable to fill some of the optional fields.

The question is, what sort of constructor should we write for such a class? Well, writing a constructor with long list of parameters is not a good choice, this could frustrate the user especially if the important fields are only a few. Moreover, this could increase the scope of error. Also, the user may provide a value accidentally to a wrong field. Long sequences of identically typed parameters can cause subtle bugs. If the user accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime.

Instead of making the desired object directly, the user calls a constructor with all of the required parameters and gets a builder object. Then, the user calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the user calls a parameter-less build method to generate the object.

Steps to create the Pattern

  1. First of all, we need to create a static nested class and then copy all the arguments from the outer class to the Builder class. Additionally, we should follow the naming convention. For example, if the class name is Cake, then builder class should be named as CakeBuilder.
  2. Next, the Builder class should have a public constructor with all the required attributes as parameters.
  3. Builder class should have methods to set the optional parameters and it should return the same Builder object after setting the optional attribute.
  4. Finally, we need to provide a build () method in the builder class that will return the Object needed by client program. In order to accomplish this, we need to have a private constructor in the Class with Builder class as argument.

Example 

For example, let’s assume an example of building a cake programmatically, follow the above steps accordingly as below.

Cake.java

public class Cake {

      private final double sugar; 
      private final double butter; 
      private final int eggs;
      private final int vanila; 
      private final double flour; 
      private final double bakingpowder; 
      private final double milk; 
      private final int cherry;

      public static class Builder {

         private double sugar;
         private double butter; 
         private int eggs;
         private int vanila; 
         private double flour; 
         private double bakingpowder; 
         private double milk; 
         private int cherry;

         //builder methods for setting property
         public Builder sugar(double cup){this.sugar = cup; return this; }
         public Builder butter(double cup){this.butter = cup; return this; }
         public Builder eggs(int number){this.eggs = number; return this; }
         public Builder vanila(int spoon){this.vanila = spoon; return this; }
         public Builder flour(double cup){this.flour = cup; return this; }
         public Builder bakingpowder(double spoon){this.sugar = spoon; return this; }
         public Builder milk(double cup){this.milk = cup; return this; }
         public Builder cherry(int number){this.cherry = number; return this; }

         //return fully build object
         public Cake build() {
            return new Cake(this);
         }
      }

      //private constructor to enforce object creation through builder
      private Cake(Builder builder) {
         this.sugar = builder.sugar;
         this.butter = builder.butter;
         this.eggs = builder.eggs;
         this.vanila = builder.vanila;
         this.flour = builder.flour;
         this.bakingpowder = builder.bakingpowder;
         this.milk = builder.milk;
         this.cherry = builder.cherry; 
      }

      @Override
      public String toString() {
         return "Cake [sugar=" + sugar + ", butter=" + butter + ", eggs=" + eggs
         + ", vanila=" + vanila + ", flour=" + flour + ", bakingpowder="
         + bakingpowder + ", milk=" + milk + ", cherry=" + cherry + "]";
      }
}

BuilderPatternTest.java

public class BuilderPatternTest {

      public static void main(String[] args) {
      
      //Creating object using Builder pattern in java
      Cake whiteCake = new Cake.Builder().sugar(1).butter(0.5).milk(0.5).build();

      //Cake is ready to eat  :lol: 
      System.out.println(whiteCake);
      }
}

Output

Cake [sugar=1.0, butter=0.5, eggs=0, vanila=0, flour=0.0, bakingpowder=0.0, milk=0.5, cherry=0]

In static class, for setting property, instead of constructors, we can also use setter method as another option.

As you can clearly see, now, a client only needs to provide the mandatory fields and the fields which are important to him. In order to create the form object now, we need invoke the CakeBuilder constructor which takes the mandatory fields. And then, we need to call the set of required methods on it and finally, the build method to get the form object.

When to use the Builder Pattern

Use the Builder pattern

  • When the algorithm for creating a complex object should be independent of the parts that make up the object and how they’re assembled.
  • When the construction process must allow different representations for the object that’s constructed.

Builder Pattern in JDK

  • lang.StringBuilder#append() (unsynchronized)
  • lang.StringBuffer#append() (synchronized)
  • nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
  • swing.GroupLayout.Group#addComponent()
  • All implementations of java.lang.Appendable.

 


Prototype Design Pattern

Prototype pattern is one of the Creational Design patterns, so it provides a mechanism of object creation. However, Prototype pattern is used when the Object creation is a costly affair. Also, it requires a lot of time and resources and if you have a similar object already existing. Therefore, this pattern provides a mechanism to copy the original object to a new object and then modify it according to our needs. Moreover, this pattern uses java cloning to copy the object.

It would be easy to understand this pattern with an example. For example, suppose we have an Object that loads data from database. Now, we need to modify this data in our program multiple times. Therefore, it’s not a good idea to create the Object using new keyword and load all the data again from the database. Hence, the better approach is to clone the existing object into a new object and then do the data manipulation.

However, Prototype Design Pattern mandates that the Object which you are copying should provide the copying feature. Obviously, It should not be done by any other class. However, whether to use shallow or deep copy of the Object properties depends on the requirements and it’s a design decision.

For example, let’s see how this can be useful. If an original object is created with a resource such as a data stream that may not be available at the time that a clone of the object is needed. Another example is, if the original object creation involves a significant time commitment, such as reading data from a database or over a network.

Object Cloning

The Prototype Pattern works on the Cloning concept. However, in Java, if you’d like to use cloning, you can utilize the clone () method and the Cloneable interface. By default, clone () performs a shallow copy. Moreover, Serializable can be used to simplify deep copying.

Furthermore, we can implement our own prototype pattern. In order to do so, we’ll create a Prototype interface that features a doClone () method.

Example

For example, below code describes how to design an advanced bike after cloning the basic bike object.

Bike.java

public class Bike implements Cloneable {

      private int gears;
      private String bikeType;
      private String model;

      public Bike() {
        bikeType="Standard";
        model= "Leopard";
        gears=4;
      }

      public Bike clone(){
         return new Bike();
      }

      public void makeAdvanced(){
         bikeType = "Advanced";
         model = "Jaguar";
         gears = 6;
      }

      public String getModel(){
         return model;
      }

      @Override
      public String toString() {
         return "Bike [gears=" + gears + ", bikeType="
         + bikeType + ", model=" + model + "]";
      }
}

PrototypeTest.java

public class PrototypeTest {

       public Bike makeJaguar(Bike basicBike){
          basicBike.makeAdvanced();
          return basicBike;
       }

       public static void main(String[] args) {

          Bike bike = new Bike();
          Bike basicBike=bike.clone();
          PrototypeTest pt = new PrototypeTest();
          Bike advancedBike= pt.makeJaguar(basicBike);
          System.out.println("Prototype Design Pattern Test-1: "+advancedBike.getModel());
          System.out.println("Prototype Design Pattern Test-2: "+advancedBike.toString());
       }
}

Output

Prototype Design Pattern Test-1: Jaguar
Prototype Design Pattern Test-2: Bike [gears=6, bikeType=Advanced, model=Jaguar]

When to Use

  • When the classes to instantiate are specified at run-time, for example, by dynamic loading; or
  • To avoid building a class hierarchy of factories that parallels the class hierarchy of products; or
  • When instances of a class can have one of only a few different combinations of state. However, It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually each time with the appropriate state.

Usage in JDK  

java.lang.Object#clone ()

That’s all about Creational Design Patterns in Java as the first part of Design Patterns in Java.

Links to Other Design Patterns 

Structural Design Patterns

Behavioral Design Patterns

Links to OOPs Design Principles & SOLID Principles

OOPs Design Principles

SOLID Design Principles

close

3 thoughts on “Creational Design Patterns In Java

  1. Wow , i learned something new here. i wish you will post more article just like this one

     

Leave a Reply

Top