Design Patterns In Java: Singleton, Factory And Builder

By Sruthy

By Sruthy

Sruthy, with her 10+ years of experience, is a dynamic professional who seamlessly blends her creative soul with technical prowess. With a Technical Degree in Graphics Design and Communications and a Bachelor’s Degree in Electronics and Communication, she brings a unique combination of artistic flair…

Learn about our editorial policies.
Updated March 7, 2024

In this tutorial we will discuss Design Patterns in Java. We will study Singleton, Factory and Builder patterns with examples and advantages:

When we solve a specific problem, we can solve it more efficiently if we have some best practices already defined. This indeed will help us to follow these best practices and develop more reliable solutions.

These best practices that can be used to develop well-proved solutions for solving problems are called “Design Patterns”. Experienced OOP software developers use design patterns to solve specific tasks.

=> Take A Look At The Java Beginners Guide Here

Design Patterns In Java

Design Patterns In Java

Design patterns were first invented by Christopher Alexander in 1977. But later on four developers namely Erich Gamma, Richard Helm, John Vlissides, and Ralph Johnson wrote a book titled, “Gang of Four-Design patterns, elements of reusable object-oriented software” in the year 1995.

From then all the design patterns came to be known as “Gang of Four Design Patterns”.

Design patterns are independent of any programming languages as they are used to solve common object-oriented design problems and are not just limited to a specific programming language. So basically it’s an idea and not an implementation.

Thus using design patterns we can develop programs that are more efficient, flexible, maintainable, and reusable.

Advantages Of Design Patterns

Enlisted below are some of the advantages of using design patterns in our applications:

  • Design patterns are reusable and can be used by multiple projects.
  • We can define system architecture using design patterns.
  • Design patterns provide transparency to the application design.
  • Design patterns are already well-tested and proved so that we can use them without any worries.
  • Design patterns allow us to build better systems and also provide clarity on system architecture.

When To Use Design Patterns

So when should we exactly use the design patterns?

We usually use a design pattern during the initial Analysis and requirement phase of SDLC (Software Development Life Cycle). When used during the analysis and requirement phase of SDLC, it provides more information to this phase. Java internally supports design patterns.

Design patterns in Java are categorized as follows:

Design patterns in Java

As far as this tutorial is concerned, we are interested only in creational design patterns.

Creational design patterns are further classified as follows:

Creational Design patterns

In this tutorial, we will discuss the following design patterns:

  • Singleton design pattern
  • Factory design pattern
  • Builder design pattern

Let’s start with a singleton design pattern in Java.

Recommended reading =>> Design Patterns for Flask based Apps

Singleton Pattern In Java

A singleton pattern is a type of creational pattern in Java. Singleton pattern is a design pattern in which only one instance of a class is present in the Java virtual machine. A singleton class (implementing singleton pattern) has to provide a global access point to get the instance of the class.

In other words, a singleton pattern restricts the instantiation of a class. Singleton pattern is used in the implementation of the logger for applications. It is also used in thread pool implementation or cache.

The Java classes, java.awt.Desktop and java.lang.runtime also use a singleton pattern.

Advantages

  • As only one instance of the singleton class is used, we save memory.
  • Also, ensures reusability as the same singleton object is used again and again.

Now let’s move onto the implementation of the singleton pattern.

Implementation Of The Singleton Pattern

As already mentioned, a singleton design pattern restricts the class with only one instance and this instance is given a global point of access. These were all classes that refer to the same object again and again.

The following UML diagram explains the Singleton pattern.

Implementation of the singleton pattern

As the above UML diagram shows, a singleton class has a single instance defined and we access it by the getInstance () method. So a singleton factory that is responsible for creating objects makes use of the getInstance method to return the same object (which is there in the class) again and again.

So how do we implement the Singleton Pattern in a Program?

We create a singleton class and have its constructor as “private” so that the class cannot be instantiated. Then we create a private instance of this singleton class inside the class itself. Then we have a special public method getInstance () that returns a singleton object to the outside world.

This implementation of this singleton class as explained above is shown in the Java program below.

class SingletonObject {
   //create an object of SingletonObject
   private static SingletonObject instance = new SingletonObject();

   //private constructor so that we cannot instantiate the class
   private SingletonObject(){}

   //returns the only available object
   public static SingletonObject getInstance(){
      return instance;
   }

   public void printMessage(){
      System.out.println("Hello from Singleton object!!!");
   }
}

public class Main {
   public static void main(String[] args) {

      //illegal statement because constructor is private
      //Compile Time Error: The constructor SingletonObject() is not visible
      //SingletonObject object = new SingletonObject();

      //call getInstance to retrieve the object available from the class
      SingletonObject object = SingletonObject.getInstance();

      //show the message
      object.printMessage();
   }
}

Output:

Implementation of singleton pattern in a program

Now if we check the main method, note that if we try to create an object of the singleton class using a new operator, the compiler will give a compilation error (see the commented code in the main method). We obtain the object of the singleton class using the getInstance () method and then we can use it as usual to access methods.

Factory Pattern In Java

The factory pattern is also called “Factory Method pattern” or “Virtual Constructor” in Java. In this pattern, we create an interface or an abstract class with method declarations, and then the concrete classes or subclasses implementing this interface or inheriting the class are responsible for creating instances of the class.

Advantages

  • The factory pattern is a type of creational pattern and is the most commonly used pattern in Java.
  • By using a factory pattern we ensure that the actual creation logic is not exposed to the outside world.

So if a class implementing a factory pattern has a method to calculate the rate of interest, then the concrete classes will implement this class and also implement the method to calculate the rate of interest.

Then there will be another class that is a factory class that will access these concrete class instances so that we are not aware of how the logic to calculate the rate of interest is implemented. We only call the method and get the output.

So when exactly can we use the Factory Method pattern?

When the parent classes decide to delegate the creation of instances to their subclasses, then we can go for a factory pattern (This is explained above). We can also use the factory method when the class doesn’t know what subclasses are to be created.

Now let’s see the implementation of the factory method pattern.

Implementation Of The Factory Pattern

As an example let’s implement a generic shape interface. We can derive various concrete classes from this interface like the circle, rectangle, etc. Then we will have a shapeFactory class that will access the concrete class objects. The UML for this pattern is shown below.

Implements of Factory Pattern

As already explained this is the UML diagram for factory pattern. Now we will implement a Java program demonstrating the factory pattern.

//Geometric_shape interface
interface Geometric_shape {
   void draw_shape();
}

//Geometric shape classes implementing Geometric_shape interface
class Rectangle implements Geometric_shape {
   @Override
   public void draw_shape() {
      System.out.println("Rectangle class::draw_shape() method.");
   }
}
class Square implements Geometric_shape {
   @Override
   public void draw_shape() {
      System.out.println("Square class::draw_shape() method.");
   }
}

class Circle implements Geometric_shape {
   @Override
   public void draw_shape() {
      System.out.println("Circle class::draw_shape() method.");
   }
}
//Factory class for Geometric_shape
class ShapeFactory {
   //shapeObject method gets  particular shapeType (circle, Square or Rectangle)
   public Geometric_shape shapeObject(String shapeType){
      if(shapeType == null){
         return null;
      }	
      //retrieve Circle object
      if(shapeType.equalsIgnoreCase("Circle")){
         return new Circle();
    
      //retrieve Rectangle object     
      } else if(shapeType.equalsIgnoreCase("Rectangle")){
         return new Rectangle();
    
      ////retrieve Square object     
      } else if(shapeType.equalsIgnoreCase("Square")){
         return new Square();
      }
      return null;
   }
}
public class Main {

   public static void main(String[] args) {
      //Create a ShapeFactory object to get different geometric shapes
      ShapeFactory shapeFactory = new ShapeFactory();

      //circle
      Geometric_shape shape_Circle = shapeFactory.shapeObject("CIRCLE");

      //draw method of Circle
      shape_Circle.draw_shape();

      //Rectangle
      Geometric_shape shape_Rectangle = shapeFactory.shapeObject("RECTANGLE");

      //draw method of Rectangle
      shape_Rectangle.draw_shape();

      //Square
      Geometric_shape shape_Square = shapeFactory.shapeObject("SQUARE");

      //draw method of square
      shape_Square.draw_shape();
   }
}

Output:

Factory Pattern - output

Builder Pattern In Java

In the Builder pattern, we use a step-by-step approach to build a complex object using small, and simple objects.

So whenever we encounter an object that cannot be created in a single step, we go for a builder pattern.

Advantages

  • Using the Builder pattern, we can separate the construction and representation of an object.
  • We also can change the internal representation of the object.
  • We can build complex designs like an entire delivery system using the builder pattern.

A practical example of a Builder pattern is the food ordering system which involved complex steps of collecting food items that are ordered, then packaging, billing, building order, and then shipping it.

In this tutorial, we will implement an example of a tablet ordering system using the Builder pattern.

Implementation Of Builder Pattern

The general UML diagram for the Builder pattern is given below.

Implementation of Builder pattern

The above diagram shows the Builder pattern UML diagram. As shown in the above diagram, we have four components in the Builder pattern.

  • Product: This represents the complex object to be built.
  • Builder Abstract class: An abstract class containing prototypes of all the functionality required to build a complex object.
  • ConcreteBuilder Class: This is a concrete class that inherits from the Builder class and creates a particular complex object. We can have as many ConcreteBuilder classes as we need.
  • Director class: This class controls the algorithms that generate the final product.

The following programming example shows the demonstration of a Builder pattern using a tablet ordering building system.

import java.util.ArrayList;  
import java.util.List;  
//Packing interface for tablets
interface Packing {  
            public String pack();  
            public int price();  
}  
//Tablet class - abstract
abstract class Tablet implements Packing{  
public abstract String pack();  
}  

//company - extends Tablet
abstract class Company extends Tablet{  
   public abstract int price();  
} 
//Lenovo tablet
class Lenovo extends Company{ 
    @Override  
        public int price(){   
                        return 541;  
      }  
    @Override  
    public String pack(){  
             return "Lenovo Yoga";  
        }         
}
//Micromax tablet
class MicroMax extends Company {  
    @Override  
        public int price(){   
                        return 338;  
    }  
    @Override  
    public String pack(){  
             return "MicroMax";  
        }         
}
 //Tablet type
class TabType {  
             private List<Packing> items=new ArrayList<Packing>();  
             //add items
             public void addItem(Packing packs) {    
                    items.add(packs);  
             }  
         //retrieve cost
             public void getCost(){  
              for (Packing packs : items) {  
                        packs.price();  
              }   
             }  
             //show all items
             public void showItems(){  
              for (Packing packing : items){  
             System.out.print("Tablet name : "+packing.pack());  
             System.out.println(", Price(in U.S.Dollars) : "+packing.price());  
          }       
            }     
}
//builder class for tablets order
class TabBuilder {  
                  public TabType buildLenovoTab(){   
                     TabType lenovo =new TabType();  
                     lenovo.addItem(new Lenovo());  
                     return lenovo;  
              }  
              public TabType buildMicroMaxTab(){  
             TabType mmx=new TabType();  
             mmx.addItem(new MicroMax());  
             return mmx;  
              }  
}
public class Main{  
 public static void main(String args[]){  
   //build the tablets order and display the order
   TabBuilder tabBuilder=new TabBuilder();  
   TabType tabtype1=tabBuilder.buildLenovoTab();  
   tabtype1.showItems();  
  
   TabType tabtype2=tabBuilder.buildMicroMaxTab();  
   tabtype2.showItems();  
 }  
}

Output:

Build Pattern - output

In the above example, we have built the complete tablet ordering system for two tablet brands i.e. Lenovo and Micromax. These are the concreteBuilder classes that inherit from the abstract class company. Then we have a TabBuilder class that builds the orders for both the tablet classes.

Frequently Asked Questions

Q #1) What are Design Patterns in Java? What are the types of design patterns in Java?

Answer: Design patterns are the best practices that can be used to develop well-tested solutions.

Java has three types of design patterns:

  • Creational design pattern: Factory pattern, Abstract Factory pattern, Singleton pattern, Builder pattern, and prototype pattern are examples of creational design patterns. These are mainly involved with the creation of objects.
  • Structural design pattern: They are mostly used for creating a class structure. Adapter, Bridge, and composite pattern are popular structural design patterns.
  • Behavioral design pattern: These provide better interaction between the objects along with the flexibility for easily extending the implementation. Observer patterns, strategy pattern, etc. are some examples of the behavioral patterns.

Q #2) Why are Design Patterns used?

Answer: Design patterns provide us a proven and tested solution model that we can use to solve complex problems. Design patterns allow us to build cohesive modules with loose coupling. Design patterns also make interaction between designers more efficient and effective.

Q #3) What are the examples of Patterns?

Answer: Examples of natural patterns are visible regularities found in nature. Natural patterns like symmetries, trees, waves, foams, stripes, cracks, etc. are some examples of natural patterns.

Q #4) Is MVC a Design Pattern?

Answer: Yes, it is a kind of design pattern using which we can build an application consisting of the data model, presentation, or view layer and controller. We can classify it more as an architectural pattern.

Conclusion

This completes our discussion on design patterns in Java. Although Java supports three types of design patterns viz. Creational, Structural, and Behavioral patterns, we are more interested in the creational design pattern.

As per the scope of this tutorial, we have discussed three examples of creational design patterns namely, singleton pattern, factory pattern, and builder pattern.

Singleton pattern is the simplest design pattern and the factory method is supposed to be a common design pattern that is widely used. The builder pattern is used to construct complex objects and is mostly used in developing complex applications.

=> Check Out The Perfect Java Training Guide Here.

Was this helpful?

Thanks for your feedback!

Leave a Comment