Category Archives: Design Patterns

Template Method Design Pattern

What is a Template Method Design Pattern

The Template Method design pattern is a behavioral design pattern that defines the outline or skeleton of an algorithm in a method but allows some steps of the algorithm to be implemented by subclasses. It promotes code reuse by providing a common structure for related algorithms while allowing specific steps to be customized in the subclasses.

It defines the skeleton of an algorithm in a base class, allowing subclasses to provide specific implementations for certain steps. It enables subclasses to customize specific parts of the algorithm while preserving the overall structure.

The Template Method pattern can be used in situations when there is an algorithm, some steps of which could be implemented in multiple different ways. In such scenarios, the Template Method pattern suggests keeping the outline of the algorithm in a separate method referred to as a template method inside a class, which may be referred to as a template class, leaving out the specific implementations of the variant portions (steps that can be implemented in multiple different ways) of the algorithm to different subclasses of this class.

Template Method lets subclasses to override/redefine certain steps of an algorithm without changing the algorithm’s structure.

The template method pattern provides a basic outline, but it allows you to customize and add your own variations to the solution.

Explanation

The Template Method design pattern is a way to create a standardized procedure for solving a problem.

It provides a set of steps that must be followed in a specific order to solve the problem. It lets subclasses to redefine certain steps of an algorithm without changing the algorithm’s structure.

The Template Method pattern is useful when you have a common algorithm with several variations, and you want to avoid code duplication among these variations. Instead of duplicating the common code in each subclass, you define the common algorithm in a base class (or abstract class) as a template method. The template method contains fixed steps of the algorithm that should not be modified and calls abstract or hook methods that the subclasses can override to provide their own implementation.

Key components of the Template Method pattern:

  1. Abstract Class (or Base Class): The abstract class defines the skeleton of the algorithm by providing a template method that orchestrates the steps of the algorithm. It may also include default implementations for some steps. It contains fixed steps of the algorithm and may include abstract methods or hook methods that can be overridden by subclasses.
  2. Concrete Classes (Subclasses): These classes inherit from the abstract class and provide concrete implementations for the abstract or hook methods. Each subclass can customize specific steps of the algorithm without changing the overall structure.
  3. Template Method: The template method is the main method in the abstract class that defines the structure of the algorithm. It calls the individual steps, including both the common steps and the ones to be overridden by subclasses.
  4. Hook Methods: Hook methods are optional methods in the abstract class that subclasses can choose to override if they need additional customization points within the algorithm.

Implementation details

The Template Method design pattern in Java can be implemented by defining a base class with a template method that implements the algorithm, and providing hooks or abstract methods for the subclasses to override. The subclasses then provide their own implementation for the hooks, if necessary to customize the behavior.

** The Template class does not necessarily have to leave the implementation to subclasses in its entirety. Instead, as part of providing the outline of the algorithm, the Template class can also provide some amount of implementation that can be considered as invariant across different implementations. It can even provide default implementation for the variant parts, if appropriate. Only specific details will be implemented inside different subclasses. This type of implementation eliminates the need for duplicate code, which means a minimum amount of code to be written.

  • Template method should consist of certain steps whose order is fixed and for some of
    the methods; implementation differs from base class to subclass. Template method should be final.
// Abstract Class (Template)
abstract class Beverage {


    // template method - that specifies the steps that define the algorithm
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    // some of the steps common
    protected void boilWater() {
        System.out.println("Boiling water");
    }

    // some of the steps, the subclasses can provide specific implementation
    protected abstract void brew();

    protected void pourInCup() {
        System.out.println("Pouring into cup");
    }

    protected abstract void addCondiments();
}

// Concrete Class 1
class Coffee extends Beverage {
    @Override
    protected void brew() {
        System.out.println("Brewing coffee");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding milk and sugar");
    }
}

// Concrete Class 2
class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("Steeping tea bag");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding lemon");
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        Beverage tea = new Tea();

        System.out.println("Preparing Coffee:");
        coffee.prepareBeverage();

        System.out.println("\nPreparing Tea:");
        tea.prepareBeverage();
    }
}

Output :

Preparing Coffee:
Boiling water
Brewing coffee
Pouring into cup
Adding milk and sugar

Preparing Tea:
Boiling water
Steeping tea bag
Pouring into cup
Adding lemon

In this example, the Beverage class is the abstract class that defines the template method prepareBeverage(), which outlines the beverage preparation process. It includes fixed steps (boilWater() and pourInCup()) and abstract methods (brew() and addCondiments()). The Coffee and Tea classes are concrete subclasses that extend Beverage and provide their specific implementations for brew() and addCondiments().

The Template Method pattern allows the common steps of the beverage preparation process to be shared among the different beverage types while allowing each type to define its unique way of brewing and adding condiments. This leads to better code organization, reusability, and maintainability.

The Template Method pattern is useful in situations where you want to provide a default implementation for a certain algorithm, while allowing subclasses to provide their own specific implementation details for certain steps.


Use cases

  • To implement the invariant parts of an algorithm once and leave it up to subclasses to
    implement the behavior that can vary.
  • When common behavior among subclasses should be factored and localized in a
    common class to avoid code duplication. You first identify the differences in the existing
    code and then separate the differences into new operations. Finally, you replace the
    differing code with a template method that calls one of these new operations.

Template Method Design Pattern – Simple implementation

Abstract Base class – Game

package com.rndayala.designpatterns.templatemethod;

public abstract class Game {
        // this is common method to initalize the video game
	public void initialize() {
		System.out.println("Welcome to EA Sports. Game Initialized..");
	}
	abstract void startPlay();
	abstract void endPlay();
	
	// template method - we mark it as final
	public final void play() {
		initialize();
		startPlay();
		endPlay();
	}

}

Concrete Class – Cricket

package com.rndayala.designpatterns.templatemethod;

public class Cricket extends Game {
	
	@Override
	void startPlay() {
		System.out.println("Cricket Game started. Enjoy the Game!");
	}

	@Override
	void endPlay() {
		System.out.println("Cricket Game Finished.");
	}
}

Concrete Class – Football

package com.rndayala.designpatterns.templatemethod;

public class Football extends Game {
	
	@Override
	void startPlay() {
		System.out.println("Football Game started. Enjoy the Game!");
	}

	@Override
	void endPlay() {
		System.out.println("Football Game Finished.");
	}
}

Client code / Demo

package com.rndayala.designpatterns.templatemethod;

public class Demo {
	public static void main(String[] args) {
		Game game = new Cricket();
		game.play();
		
		System.out.println();
		
		game = new Football();
		game.play();
	}
}

Output :

Welcome to EA Sports. Game Initialized..
Cricket Game started. Enjoy the Game!
Cricket Game Finished.

Welcome to EA Sports. Game Initialized..
Football Game started. Enjoy the Game!
Football Game Finished.

The Template Method design pattern is used in situations where you want to define the skeleton of an algorithm, but allow subclasses to provide the implementation for some of the steps.

When to use the template method design pattern is when you are implementing a common task that has multiple steps, and some of the steps may change based on specific requirements. By using template method pattern, you can define the basic steps and let subclasses implement the specific details for each step. This way, you can maintain the common interface, but still provide the flexibility to change the algorithm as needed.


In Java, the Template Method pattern is widely used to define the structure of algorithms while allowing subclasses to provide specific implementations for certain steps.

Singleton Design Pattern

What is a Singleton Design Pattern

Sometimes it’s important for some classes to have exactly one instance. There are many objects we only need one instance of them and if we, instantiate more than one, we’ll run into all sorts of problems like incorrect program behavior, overuse of resources, or inconsistent results.

There are only two points in the definition of a singleton design pattern,

  • There should be only one instance allowed for a class and
  • We should allow global point of access to that single instance.

From the definition, it seems to be a very simple design pattern but when it comes to
implementation, it comes with a lot of implementation concerns.

Explanation of the pattern

With the Singleton pattern, you define a private constructor in the class, which ensures that no one can create a new instance of the class from outside. You also define a public method called “getInstance” that returns the single instance of the class.

The first time the method is called, it creates a new instance of the class. Any subsequent calls to the method return the same instance that was created the first time. In this way, you ensure that there is only one instance of the class.

The Singleton pattern can be implemented in various ways, but it is essential to ensure that only one instance of the class is created, and that it is accessible from anywhere in the code. To achieve this, it is common to use lazy initialization, where the instance is created only when it is first needed.

In summary, the Singleton pattern can be useful for creating shared resources in a system where it is important to maintain a single instance and ensure that it is accessible from anywhere in the code. It can also be used to control the instantiation of a class, ensuring that it is only created once, and to provide a single point of access to the instance.

Why Lazy Initialization

Lazy initialization will be beneficial when we want to delay the initialization until it is not
needed, because if we use eager initialization and if initialization fails there is no chance
to get the instance further. While in lazy initialization we may get it in second chance. In Lazy initialization we will not get instance until we call getInstance () method while in
eager initialization it creates instance at the time of class loading.


How to implement Singleton pattern

package com.rndayala.designpatterns.singleton;

// Author : Raghunath Dayala

/* Singleton is a design pattern that restricts a class to have ONLY one instance, 
 * with a global point of access to it.
 * Useful when you want to limit the number of instances of a class that can exist in the system.
 * This can be useful in situations  where you want to maintain a single instance of a class 
 * to represent a shared resource, such as a  logging service, database connection or a configuration manager.
 * Ref : Check my Kindle library
 */

public class Singleton {
	// private static variable
	private static Singleton instance = null;
	
	// a private constructor that ensures that it cannot be instantiated directly from outside the class.
	private Singleton() {
		System.out.println("Creating Singleton class object..");
	}
	
	// public static method called getInstance is provided, 
	// which returns the  single instance of the class.  
	// The first time the getInstance is invoked, it creates and returns the object.
	// Any subsequent calls returns the same instance created the first time.
	public static Singleton getInstance() {
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}

/* Problems :
 * 1. the above implementation is not thread safe.
 * 2. We can still be able to create new objects using Reflection.
 * 3. We can be able to create new objects using Cloning.
 * 4. When we do serialization/de-serialization, we get new objects.
*/

In above example, the Singleton class has a private constructor that ensures that it cannot be instantiated directly. Instead, a public static method called getInstance is provided, which returns the single instance of the class.

The first time the getInstance method is called, it creates a new instance of the Singleton class by calling the private constructor. Subsequent calls to getInstance return the same instance that was created the first time.

Multi-threaded Singleton implementation

Singleton will work properly in multithreaded environment only if eager instantiation has been done because in this case instance creation will happen at the time of class loading only. But for Lazy instantiation we will have to take care of multiple things. If we want to delay the instantiation because of cost, we use to go with lazy.

Simple Implementation :

package com.rndayala.designpatterns.singleton;

/**
 * Singleton in multi-threaded environments.
 * the behavior of Singleton instance when two threads are 
 * getting executed by comparing their hash code values.
 * 
 * The following code works only in Java 8.
 * @author rndayala
 */

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingletonT {
	
	private static SingletonT instance = null; // lazy initialization
	
	private SingletonT() {
		System.out.println("Creating..");
	}
	
	// When you run the above program many times you will notice that in multithreaded environment,
	// sometimes Singleton principle works, but sometimes it violates.

	public static SingletonT getInstance() {
		if (instance == null) {
			instance = new SingletonT();
		}
		return instance;
	}



	static void useSingleton() {
		SingletonT singleton = SingletonT.getInstance();
		print("Singleton", singleton);
	}
	
	static void print(String name, SingletonT obj) {
		System.out.println(String.format("Object : %s, hashcode : %d", name, obj.hashCode()));
	}
	
	public static void main(String[] args) {
		ExecutorService service = Executors.newFixedThreadPool(2);
		service.submit(SingletonT::useSingleton); // Object : Singleton, hashcode : 918401706
		service.submit(SingletonT::useSingleton); // Object : Singleton, hashcode : 918401706
		service.shutdown();
	}

}

/* observations :
 * When you run the above program many times you will notice that in multithreaded environment,
 * sometimes Singleton principle works but sometimes it violates.
 * Fix : After applying synchronized keyword in the getInstance () method, the program will execute 
 * properly without any issue but in Java.
*/

When you run the above program many times you will notice that in multithreaded environment, sometimes Singleton principle works, but sometimes it violates. Therefore we need to synchronize the getInstance () method as shown below :

	// When you run the above program many times you will notice that in multithreaded environment,
	// sometimes Singleton principle works, but sometimes it violates.
	// Fix : add synchronized keyword to the getInstance() method

	public static synchronized SingletonT getInstance() {
		if (instance == null) {
			instance = new SingletonT();
		}
		return instance;
	}

After applying synchronized keyword in the getInstance () method the program will execute properly without any issue.


Double Checked Locking

Instead of synchronizing whole method we can synchronize only the block of code which is affected while creating instance to escape the extra overhead as below :

	// Don't synchronize getInstance() method completely.
	// Synchronize only the block of code which is affected while creating instance.
	public static SingletonT getInstance() {
		if (instance == null) {
			synchronized (SingletonT.class) {
				instance = new SingletonT();
			}
		}
		return instance;
	}

From the above code we have narrowed down the scope of synchronization for performance reasons. But the above code can cause issues due to thread switching.

So to make sure no other thread has already acquired the lock we will apply one more check after acquiring the lock as shown below. This method is called Double Checked Locking.

	// Don't synchronize getInstance() method completely.
	// Synchronize only the block of code which is affected while creating instance.
	public static SingletonT getInstance() {
		if (instance == null) {
			synchronized (SingletonT.class) {
				// double checked locking
				if (instance == null) {
					instance = new SingletonT();
				}
			}
		}
		return instance;
	}

Sometimes double checked locking also breaks the Principle of Singleton. It may return an instance in half-initialized state.

To address this situation use volatile keyword at the time of instance declaration. Value of volatile variable will be published only when the change completes. Change to write
operation happens before read operation in volatile variable. In short all threads will see the same value of variable.

private static volatile SingletonT instance = null; // lazy initialization

Reflection – Singleton implementation violation ? How to Fix ?

In Java, you can violate the Singleton pattern’s intended behavior using reflection.

Reflection allows you to access and modify the private constructors and fields of a class, which can lead to the creation of multiple instances of the Singleton class, thus violating the pattern.

Here’s an example of how the Singleton pattern can be violated using reflection in Java:

import java.lang.reflect.Constructor;

public class Singleton {

    private static Singleton instance;

    private Singleton() {
        // Private constructor
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    // Other methods and fields...
}

public class Main {

    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = null;

        try {
            // Using reflection to access the private constructor
            Constructor<Singleton> constructor 
                              = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            singleton2 = constructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(singleton1); // Output: Singleton@hashcode1
        System.out.println(singleton2); // Output: Singleton@hashcode2
    }
}

In the example above, we try to access the private constructor of the Singleton class using reflection and create a new instance. As a result, singleton2 is not the same instance as singleton1, and we have violated the Singleton pattern’s intent.

To protect against this kind of reflection-based Singleton pattern violation, you can modify the Singleton class to throw an exception if someone tries to create a new instance using reflection:

public class Singleton {

    private static Singleton instance;

    private Singleton() {
        if (instance != null) {
            throw new RuntimeException("Use getInstance() method to get the single instance.");
        }
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    // Other methods and fields...
}

By adding the check inside the private constructor, any attempt to create a new instance through reflection will result in an exception, preserving the Singleton pattern’s integrity. However, it’s essential to be cautious when using reflection and design patterns together, as it can lead to unexpected behavior and undermine the patterns’ intended benefits.

Clone – Singleton implementation violation ? How to Fix ?

If we try to make instance by cloning it, the generated hash code of cloned
copy doesn’t match with the actual object so it also violates the Singleton principle of having a single instance.

Here’s an example to illustrate the issue:

public class Singleton implements Cloneable {

    private static Singleton instance;

    private Singleton() {
        // Private constructor
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // Other methods and fields...
}

public class Main {

    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = null;

        try {
            // Cloning the singleton object
            singleton2 = (Singleton) singleton1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        System.out.println(singleton1); // Obj: singleton1, hashcode: 366712642
        System.out.println(singleton2); // Obj: clone, hashcode: 1442407170
    }
}

In this example, we implement the Cloneable interface in the Singleton class, and we override the clone() method to call the super.clone() method. The generated hash code of cloned copy doesn’t match with the actual object so it also violates the Singleton principle.

To address this issue, you may consider throwing an exception in the clone() method to prevent cloning altogether:

public class Singleton implements Cloneable {

    // Singleton implementation...

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException("Cloning of Singleton objects is not allowed.");
    }

    // Other methods and fields...
}

By throwing a CloneNotSupportedException, you explicitly prohibit cloning of the Singleton objects and maintain the integrity of the Singleton pattern. However, it’s important to note that the use of Cloneable and clone() method can be controversial in Java, and it is generally recommended to avoid using them in favor of other approaches like copy constructors or factory methods for object duplication.

How to fix: Throw CloneNotSupportedException from the clone () method if someone
tries to make other instance of it.


Bill Pugh method – Singleton Implementation

The Bill Pugh Singleton pattern, also known as the Initialization-on-demand Holder Idiom, is an improvement over the traditional Singleton pattern.

It provides a simpler and more thread-safe way to implement a Singleton in Java without the need for explicit synchronization. This pattern takes advantage of the Java class-loading mechanism to ensure that the Singleton instance is created lazily and safely when the class is loaded.

We use inner static class approach in this implementation. The inner static class encapsulates the Singleton instance, and its instantiation logic is taken care of by the JVM, reducing the need for explicit synchronization or volatile variables.

Bill Pugh implementation – thread safe, no need of explicit synchronization or volatile variable. The inner static class shields the Singleton instance from being created through reflection, as the constructor remains private.

Here’s the implementation of the Bill Pugh Singleton pattern:

public class Singleton {

    // Private constructor to prevent instantiation from other classes
    private Singleton() {
        // Initialization code (if any) goes here
    }

    // Inner static helper class responsible for holding the Singleton instance
    private static class SingletonHolder {
        // The Singleton instance is created when the class is loaded
        private static final Singleton INSTANCE = new Singleton();
    }

    // Public static method to get the Singleton instance
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // Other methods and fields...
}

In this implementation, the Singleton class has a private constructor to prevent direct instantiation. The Singleton instance is stored as a static field within a nested static class called SingletonHolder. The INSTANCE field is initialized during the class-loading phase, which is guaranteed to be thread-safe by the Java Virtual Machine.

When getInstance() is called, it returns the Singleton instance held by the SingletonHolder, ensuring that only one instance is created throughout the application’s lifecycle.

Here’s how you can use the Bill Pugh Singleton pattern:

public class Main {

    public static void main(String[] args) {
        // Get the Singleton instance
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        // Both instances are the same
        System.out.println(singleton1 == singleton2); // Output: true
    }
}

This approach provides better performance and avoids unnecessary synchronization overhead because the Singleton is initialized lazily and only when needed.

Nowadays, this Bill Pugh method is widely used and considered a best practice for creating Singleton instances.


enum implementation of Singleton pattern

In Java, you can implement the Singleton pattern using an enum.

Enums in Java are implicitly singleton by design, as they only allow a fixed set of predefined instances, and there can be no more than one instance of each enum constant. This property makes enums a natural fit for implementing a singleton.

Joshua Bloch suggests the use of Enum to implement Singleton design pattern as Java ensures that any enum value is instantiated only once in a Java program. Since Java Enum values are globally accessible, so is the singleton.

The drawback is that the enum type is somewhat inflexible; for example, it does not allow lazy initialization.

Here’s how you can implement the Singleton pattern using an enum :

public enum SingletonEnum {
    INSTANCE;

    // Any additional fields or methods for the Singleton can be added here
    // ...

    // Example method
    public void doSomething() {
        // Implement functionality here
    }
}

In this implementation, SingletonEnum is an enum that contains a single instance called INSTANCE. When the SingletonEnum class is loaded, the INSTANCE constant is initialized, and it remains the only instance throughout the application’s lifecycle.

In the context of implementing the Singleton pattern using an enum, the INSTANCE is a single constant instance of the enum type. In Java, enum constants are implicitly static and final, which means they can only be created once during the class loading and cannot be modified afterward. As a result, an enum with a single constant effectively serves as a singleton.

INSTANCE represents the sole instance of the SingletonEnum class. The enum constant name (INSTANCE in this case) can be any valid Java identifier, but by convention, INSTANCE is commonly used to signify that it represents the single instance of the singleton.

You can use the SingletonEnum instance like this:

public class Main {

    public static void main(String[] args) {
        SingletonEnum singleton1 = SingletonEnum.INSTANCE;
        SingletonEnum singleton2 = SingletonEnum.INSTANCE;

        // Both instances are the same
        System.out.println(singleton1 == singleton2); // Output: true

        // Call methods on the Singleton instance
        singleton1.doSomething();
    }
}

As enum constants are inherently thread-safe and guaranteed to be initialized only once, using an enum for the Singleton pattern eliminates the need for explicit synchronization and ensures a simple, efficient, and safe singleton implementation in Java.

As with any enum, the SingletonEnum’s instance is implicitly thread-safe and immune to issues related to reflection or serialization, making this approach one of the simplest and most effective ways to implement a thread-safe Singleton pattern in Java.

Enum Singleton doesn’t violate principle of Singleton in any case described above.

Design Patterns Introduction

What are Design Patterns

A design pattern is a reusable solution to a commonly occurring problem in software design. It represents a general, proven approach that can be applied to various situations to address specific design challenges.

The design patterns are language independent strategies for solving common object-oriented design problems.

Design patterns are an essential tool for software development that can help programmers write more organized, efficient, and reusable code.

They are like pre-made templates for solving common problems that arise in software development, offering a standardized and proven solution for each problem. By using design patterns, programmers can save time, reduce the risk of bugs, and improve the overall quality of their code.


They are usually divided into categories such as creational, structural, and behavioral patterns, each with its own unique set of solutions.

By learning design patterns in Java, developers can deepen their understanding of object-oriented concepts and improve their ability to design and implement complex software.


Why learn Design Patterns

When you make a design, you should know the names of some common solutions. Learning design patterns is good for people to communicate each other effectively.

SUN suggests GOF (Gang of Four—four pioneer guys who wrote a book named
“Design Patterns”- Elements of Reusable Object-Oriented Software), so we use that book as our guide to describe solutions.

Design patterns are an essential tool for software development that can help programmers write more organized, efficient, and reusable code.

They are like pre-made templates for solving common problems that arise in software development, offering a standardized and proven solution for each problem. By using design patterns, programmers can save time, reduce the risk of bugs, and improve the overall quality of their code.


Categories of Design Patterns

Design patterns are generally categorized into three main types:

1. Creational Patterns: These patterns are used to create objects and classes in a way that is suitable for a particular situation. Creational design patterns provide solution to instantiate an object in the best possible way for specific situations.

  • Singleton Pattern
  • Factory Pattern
  • Abstract Factory Pattern
  • Builder Pattern
  • Prototype Pattern

2. Structural Patterns: These patterns are used to arrange classes and objects to form larger structures. Structural patterns provide different ways to create a class
structure, for example using inheritance and composition to create a large object from
small objects.

  • Adapter Pattern
  • Composite Pattern
  • Proxy Pattern
  • Flyweight Pattern
  • Facade Pattern
  • Bridge Pattern
  • Decorator Pattern

3. Behavioral Patterns: These patterns are used to describe the ways in which objects interact and communicate with each other. Behavioral patterns provide solution for the better interaction between objects and how to provide lose coupling and flexibility to extend easily.

  • Template Method Pattern
  • Mediator Pattern
  • Chain of Responsibility Pattern
  • Observer Pattern
  • Strategy Pattern
  • Command Pattern
  • State Pattern
  • Visitor Pattern
  • Iterator Pattern
  • Interpreter Pattern
  • Memento Pattern

These categorizations are a useful way to understand the different types of design patterns and their intended uses.