Tuesday, July 22, 2025

GoF (Gang of Four) or OOPS design patterns- inshort

Here’s a concise yet practical guide to the 23 GoF (Gang of Four) design patterns, grouped by category, with:

When to use
🏛️ Architectural use case examples


🔷 1. Creational Patterns

Concerned with object creation mechanisms, hiding the logic and making the system independent of how objects are created.

Pattern

When to Use

Architecture Use Case

Singleton

When you need one and only one instance of a class

Configuration, Logging, Connection Pool

Factory Method

When you need to create objects without exposing instantiation logic

Plugin loader, Task Scheduler

Abstract Factory

When you need to create families of related objects

UI Toolkits (e.g., Dark/Light Theme components)

Builder

When you need to build a complex object step by step

Building DTOs, Configuring Kafka consumers

Prototype

When object creation is costly and you want to clone instead

Cloning a configured workflow template or entity state


🔷 2. Structural Patterns

Concerned with object composition, ensuring that classes and objects work together to form larger structures.

Pattern

When to Use

Architecture Use Case

Adapter

When interfaces are incompatible but need to work together

Integrating legacy system with new API

Bridge

When you want to separate abstraction from implementation

Decouple UI control and rendering logic

Composite

When you want to treat individual objects and compositions uniformly

Tree structure like a file system or menu

Decorator

When you want to add responsibilities to objects dynamically

Logging, metrics around existing service methods

Facade

When you want to provide a simplified interface to a complex subsystem

Simplified APIs over a complex service layer

Flyweight

When you have lots of objects with shared state to optimize memory

Reusing icons, font objects in UI rendering

Proxy

When you need a placeholder to control access to another object

Lazy loading, security checks, or caching


🔷 3. Behavioral Patterns

Concerned with communication between objects.

Pattern

When to Use

Architecture Use Case

Chain of Responsibility

When you want multiple objects to handle a request in a chain

Request validation chain, Middleware pipelines

Command

When you need to encapsulate requests as objects

Undo/Redo, Task queues

Interpreter

When you need to evaluate sentences in a language

Expression parsers, configuration DSL

Iterator

To access elements of a collection sequentially without exposing underlying structure

Database cursor, File reader

Mediator

When you want to centralize complex communication between objects

Chat rooms, Event buses

Memento

To restore object state to a previous state

Undo operations, version control

Observer

When multiple objects need to be notified of state changes

Event listeners, messaging subscribers

State

When an object needs to change behavior when its state changes

Stateful workflows, TCP state machine

Strategy

When you want to define a family of algorithms, encapsulate each one

Encryption strategies, Sorting algorithms

Template Method

When you want to define the skeleton of an algorithm, deferring steps to subclasses

Report generation with customizable steps

Visitor

When you want to perform operations on elements of object structure without changing the classes

Code generation, XML processing


📘 Quick Mapping: Architecture Use Cases by Pattern

Area

Useful Patterns

RESTful APIs

Facade, Decorator, Chain of Responsibility

Microservices

Proxy, Mediator, Observer, Strategy

UI Components

Composite, Flyweight, Adapter, Bridge

Cloud Infrastructure

Singleton (for global config), Builder (resource templates)

Message Queues/Event-Driven

Observer, Command, Mediator

Security

Proxy, Chain of Responsibility, Strategy (authN/authZ)

ETL Pipelines

Chain of Responsibility, Strategy, Template Method

Monitoring/Logging

Decorator, Observer

Workflow Engine

State, Command, Memento, Interpreter




Creational Patterns

🔹 Singleton

Answer:

I chose Singleton because we needed to ensure a single global instance of a class like a configuration manager or logger.
It fits well in the architecture as it helps us centralize shared state and avoid redundant initialization, especially in cases like managing DB connection pools or global config.
It also keeps the design clean and efficient, avoiding unnecessary object creation.


🔹 Factory Method

Answer:

I chose Factory Method because we needed to create objects based on runtime input without exposing the instantiation logic.
It fits well in the architecture as it helps us encapsulate object creation and adhere to the Open/Closed Principle, especially in scenarios like instantiating different notification types (Email, SMS, Push).
It also keeps the design extensible and loosely coupled.


🔹 Builder

Answer:

I chose Builder because we needed to construct complex objects with optional fields and immutable design.
It fits well in the architecture as it helps us build configurations or DTOs in a readable and safe manner, especially in API request/response object construction or job definitions.
It also keeps the design clean and fluent.


Structural Patterns

🔹 Adapter

Answer:

I chose Adapter because we needed to integrate a legacy system with a new interface without changing the old code.
It fits well in the architecture as it helps us bridge incompatible APIs, especially when wrapping a SOAP service with a REST interface.
It also keeps the design flexible and backward-compatible.


🔹 Decorator

Answer:

I chose Decorator because we needed to add additional behavior like logging or validation without modifying core logic.
It fits well in the architecture as it helps us layer responsibilities dynamically, especially in Spring AOP or request interceptors.
It also keeps the design modular and open for extension.


🔹 Facade

Answer:

I chose Facade because we needed to simplify access to a complex subsystem for clients.
It fits well in the architecture as it helps us expose a clean API over multiple microservices or modules, especially in API Gateway or Orchestrator services.
It also keeps the design easy to use and maintain.


Behavioral Patterns

🔹 Chain of Responsibility

Answer:

I chose Chain of Responsibility because we needed to process a request through a customizable sequence of handlers.
It fits well in the architecture as it helps us build a middleware-style processing pipeline, especially in authentication → validation → execution chains in request filters.
It also keeps the design modular and flexible.


🔹 Strategy

Answer:

I chose Strategy because we needed to swap algorithms or business rules at runtime without changing the context.
It fits well in the architecture as it helps us plug in different pricing models or filtering rules, especially in e-commerce engines or data parsers.
It also keeps the design clean, testable, and open for new strategies.


🔹 Observer

Answer:

I chose Observer because we needed to notify multiple systems when an event occurs.
It fits well in the architecture as it helps us decouple event emitters from subscribers, especially in event-driven systems like Kafka consumers or audit logs.
It also keeps the design scalable and reactive.


🔹 State

Answer:

I chose State because we needed to handle behavior that changes based on internal state.
It fits well in the architecture as it helps us model state transitions in workflows or finite state machines, especially in order processing or protocol handling.
It also keeps the design structured and avoids complex conditionals.


No comments:

Post a Comment