
Software design pattern is used throughout the software development lifecycle. It helps during the analysis and requirements phase.
Every software engineer should use the software design patterns to develop the software. It helps us to design quality software. Remember that if we design software using design patterns, the experience developer can easily understand the developed software, software code, software flow.
And design pattern also helps the new programmer or developer to understand the software code.
There are many design patterns are available which can be used in designing:
Table of Contents
What is Factory Method Design Pattern?
In factory pattern method we define an interface or abstract class and we give the responsibility of creating instances of the class to its subclasses. We use factory pattern to define various functions, we create a factory method in which we create object.
In this pattern the subclasses decide how the parent object is created and what types of objects are included in the parent. In simple words we can say that factory pattern is related to object creation.
Advantages of Factory design pattern
- You can promote loose-coupling by using the Factory Pattern.
- By using factory pattern we can get more readable code where multiple constructors are present and constructors can be available for different purposes.
Shape.java
package com.geekcer;
public interface Shape {
void draw();
}
Square.java
package com.geekcer;
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square draw() method.");
}
}
Rectangle.java
package com.geekcer;
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle draw() method.");
}
}
Circle.java
package com.geekcer;
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle draw() method.");
}
}
ShapeFactory.java
package com.geekcer;
public class ShapeFactory {
//use getShape method to get object of type shape
public Shape getShape(String shapeType) {
if(shapeType == null) {
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
FactoryPatternRun.java
package com.geekcer;
public class FactoryPatternRun {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactory();
// Gets the Circle object
Shape circle = factory.getShape("CIRCLE");
//call draw() method of Circle
circle.draw();
// Gets the Rectangle object
Shape rectangle = factory.getShape("RECTANGLE");
//call draw() method of Rectangle
rectangle.draw();
// Gets the Square object
Shape square = factory.getShape("SQUARE");
//call draw() method of square
square.draw();
}
}
Output: Circle draw() method. Rectangle draw() method. Square draw() method.
What is Singleton Design Pattern?
Singleton design pattern ensures that there will be only one instance of a class, we can create only one object of the class. If we use singleton pattern then a class itself can control its instantiation or number of object creation.
It is simple form of design pattern and it is useful when we need only one object of a class in whole application.
Intent of singleton design pattern
- We can create only one instance of a class.
- We can easily access any single instance of the class.
- The class will handle the object creation itself.
- If we use singleton pattern we can control the number of instances of a class.
Is singleton thread safe?
Singleton pattern only deals with object creation, not thread safety. Hence it is not thread safe.
Can singleton be thread safe?
Of course you can make the singleton class thread safe by synchronizing the getInstance() method.
Best way to implement Singleton
The following program will demonstrate how to implement a Singleton in the most efficient way possible. For the singleton, we’re making the constructor private.
GeekClass.java
package com.geekcer;
public class GeekClass {
// Create an object of GeekClass
private static GeekClass instance = new GeekClass();
// Make the constructor private so that this class cannot be instantiated
private GeekClass(){}
// Get the object available
public static GeekClass getInstance() {
return instance;
}
public void showMessage(){
System.out.println("Hello Geek!");
}
}
GeekDemo.java
package com.geekcer;
public class GeekDemo {
public static void main(String[] args) {
GeekClass obj = GeekClass.getInstance();
obj.showMessage();
}
}
Output: Hello Geek!
What are the main drawbacks of singleton design pattern?
- We can create multiple references to the same object.
- Since singleton can be treated as a global variable, in this case it may accidentally cause a change in one place to be reflected in another.
- All classes that use global variables are tightly coupled.
What is Prototype Design Pattern?
The prototype is used to construct an object in the Prototype pattern. To put it another way, when a class generates an object, it creates a clone of it and returns it as a class object. When needed, the clone technique has been utilized to clone prototypes.
When an Employee class object is generated, the Employee class makes a clone of it and returns it as an Employee class object.
What is the purpose of prototype pattern?
What is the purpose of prototype pattern? You may use the prototype design pattern to build a new instance of a class from an existing one.
There are following other purpose of prototype pattern.
- To make the process of generating an object easier.
- In this approach, we can add or delete the objects at run-time.
- To reduce the cost of creating a object.
- Create an instance of the dynamically loaded class.
Prototype Design Pattern Implementation Steps
- Create an abstract class/interface and add a cloning method to it.
- Extend the abstract class or implement the interface to create a class.
- Override the method and write cloning code to it (Create new object with similar data).
Prototype.java
package com.geekcer;
public interface Prototype{
Prototype clone();
}
Employee.java
package com.geekcer;
public class Employee implements Prototype {
private int empNo;
private String empName;
public Employee(int empNo, String empName) {
this.empNo = empNo;
this.empName = empName;
}
@Override
public Prototype createClone() {
return new Employee(empNo, empName);
}
@Override
public String toString() {
return "Employee No: " + empNo + ", Employee Name: " + empName;
}
}
PrototypeExample.java
package com.geekcer;
public class PrototypeExample {
public static void main(String[] args) {
Employee employee = new Employee(10, "SCOTT");
Employee employeeCloned = (Employee)employee.createClone();
System.out.println("Original: " + employee);
System.out.println("Prototype: " + employeeCloned);
}
}
Output: Original: Employee No: 10, Employee Name: SCOTT Prototype: Employee No: 10, Employee Name: SCOTT
What is Builder Design Pattern?
The Builder design pattern is an alternative to the Factory and Abstract Factory design patterns for creating huge objects. It was created to address the issue with the Factory and Abstract Factory design patterns when the object has too many fields.
The builder pattern distinguishes the creation of an object from its representation.
Advantages of Builder Design Pattern
- It gives you more control over the design of complicated objects.
- Some optional arguments are forced to be transmitted as NULL in the factory pattern. As a result, the builder pattern avoids this issue.
- Object creation is done step by step in this design.
Example program of builder design pattern
A builder class creates the final product one step at a time. This builder is independent by other objects.
Employee.java
package com.geekcer;
public class Employee {
// All final attributes
private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private Employee(Builder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Employee Info: " + this.firstName + ", " + this.lastName + ", " + this.age;
}
public static class Builder {
private final String firstName;
private final String lastName;
private int age;
public Builder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Employee build() {
Employee employee = new Employee(this);
validateEmployeeObject(employee);
return employee;
}
private void validateEmployeeObject(Employee employee) {
System.out.println("Employee Validated!");
}
}
}
Main.java
package com.geekcer;
public class Main {
public static void main(String[] args) {
Employee employee1 = new Employee.Builder("Scott", "Janson").age(30).build();
System.out.println(employee1);
Employee employee2 = new Employee.Builder("John", "Dev").age(35).build();
System.out.println(employee2);
}
}
Output: Employee Validated! Employee Info: Scott, Janson, 30 Employee Validated! Employee Info: John, Dev, 35
Read More
Immutable Class in Java
Software Performance Testing