0% found this document useful (0 votes)
16 views265 pages

Spring Boot Design Patterns Overview

Uploaded by

sagarparida983
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views265 pages

Spring Boot Design Patterns Overview

Uploaded by

sagarparida983
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Design Patterns Use Cases

(Java And Spring)

Creational

1. Singleton

a. Where centralised access, a single point of control, resource sharing, or


global coordination is needed.

b. We can have a single class for inventory management, restaurant


management

2. Builder

a. When an object has many optional fields or parameters.

b. To avoid a telescoping constructor (many overloaded constructors) and


passing unwanted params during initialisation.

3. Factory

a. A Factory Pattern defines an interface for creating an object but lets


subclasses decide which class to instantiate.

b. We can pick one among multiple strategies and instances

4. Abstract Factory

a. It's essentially a factory of factories — it creates related objects grouped


under a common theme. Can be used in combination with template pattern
to eliminate duplicate code.

5. Object Pool

a. Reusing objects that are expensive to create

6. Prototype

Design Patterns Use Cases (Java And Spring) 1


a. create new objects by copying existing ones (cloning) instead of
instantiating new ones from scratch

Behavioural

1. Adapter

a. The Adapter Design Pattern is a structural pattern used to allow the


interface of an existing class to be used as another interface. It acts as a
bridge between two incompatible interfaces.

b. Imagine you are integrating a third-party Media Player into your


application, but your app expects a different interface. Instead of rewriting
existing code, you write an adapter to connect both.

c. We can use a factory to pick the best version among the adapters

d. It will pick the best among multiple implementations

e. Autowired annotation and Map can be used in spring boot to get the
corresponding instance with the Component qualifier name

2. Bridge

a. The Bridge Design Pattern is a structural pattern used to decouple


abstraction from implementation, so that the two can vary independently.

🎯 Why People Say "Adapter of Adapter"


This informal phrase may come up because:

The Bridge pattern introduces an abstraction layer on top of another


abstraction, much like multiple adapters chained together.

In some complex architectures, you may build adapters that use other
adapters internally (e.g., in a plug-in system), and the result starts
resembling a Bridge structurally.

From a bird’s eye view, both patterns are solving integration problems —
Bridge for decoupling, Adapter for compatibility.

Design Patterns Use Cases (Java And Spring) 2


You want to avoid a combinatorial explosion of classes.

You want to decouple abstraction from implementation for better


flexibility.

You expect to change or extend both abstraction and implementation


independently.

Adapter pattern: You already have a StripeSDK and want to adapt it to


your internal interface PaymentProcessor.

Bridge pattern: You’re designing the system from scratch to support


multiple payment types (Stripe, Razorpay, PayPal) and multiple payment
methods (card, wallet, UPI) with separate hierarchies.

Autowired annotation and Map can be used in spring boot to get the
corresponding instance with the Component qualifier name and type

3. Decorator ( Wrapper )

a. The Decorator Design Pattern (also known as the Wrapper Pattern) is a


structural pattern used to dynamically add behavior or responsibilities to
an object without modifying its code. This is especially useful when you
want to extend functionality in a flexible and reusable way, without
subclassing.

b. We want to notify users via email, but also allow optional SMS and Slack
notifications without altering the original notifier.

c. Reusing an object withour modifying it

d. We can use Decorator via Configuration (Bean annotation) or Primary


annotation

Scenario Use Decorator Use Observer

Add retry, logging, or email formatting ✅ Yes ❌ No


Notify multiple systems (email, SMS, etc.) ❌ No ✅ Yes
Modify behavior of a single notifier ✅ Yes ❌ No
Broadcast events to multiple listeners ❌ No ✅ Yes

🧩
Design Patterns Use Cases (Java And Spring) 3
🧩 Pattern Intent
Pattern Purpose

Dynamically adds behavior to a single object by wrapping it.


Decorator
Example: Retry, logging, analytics

Publishes updates to multiple subscribers when an event occurs.


Observer Example: Send email, SMS, and webhook in response to a user
signup

4. Composite

a. The Composite Design Pattern is a structural pattern used to treat


individual objects and compositions of objects uniformly. It allows you to
build tree-like structures where nodes can be either leaf (basic objects) or
composites (containers of other objects).

b. File And Directories

5. Filter (Criteria)

a. The Filter (Criteria) Design Pattern, a structural pattern (often treated as


behavioral as well), allows you to filter a set of objects using different
criteria and chaining them using logical operations such as AND, OR, NOT.

6. Proxy

a. The Proxy Design Pattern provides a surrogate or placeholder for another


object to control access to it.

b. Used for:

Access control (e.g. protecting real objects)

Lazy initialization (e.g. expensive object creation)

Remote proxies (e.g. RMI)

Logging / auditing / caching

7. Flyweight

a. The Flyweight Design Pattern is a structural pattern used to minimize


memory usage or computational expenses by sharing as much data as
possible with similar objects.

🔧
Design Patterns Use Cases (Java And Spring) 4
🔧 When to Use
You have many objects that consume a lot of memory.

Most object data is intrinsic (shared) and only a small part is extrinsic
(context-specific).

You want to reuse objects instead of creating new ones each time.

🧪 Real-World Use Cases


Use Case Description

Characters share font info (intrinsic), but position is


Text Editor (characters)
extrinsic.

Reuse similar game pieces instead of creating new


Game Trees (chess, go)
ones.

One icon object rendered in many places with


Icons in UI
different positions.

Reuse particle shape, size etc., change position/color


Particle systems
only.

Map rendering (e.g., Google


Reuse marker shapes/icons across locations.
Maps)

8. Facade

🧩 What is the Facade Pattern?


The Facade pattern provides a simplified interface to a complex subsystem.
It's useful when:

You want to hide system complexity from the client.

You want to provide a unified interface to multiple components.

Structural

1. Chain Of Responsibility

Design Patterns Use Cases (Java And Spring) 5


a. The Chain of Responsibility (CoR) design pattern allows you to pass a
request along a chain of handlers until one of them handles it. It’s useful
when multiple objects can handle a request and you want to decouple the
sender and receiver.

b. Validator Chain, Logger Chain, Middleware

2. Command (Action Or Transaction)

a. The Command Design Pattern encapsulates a request as an object,


thereby allowing you to parameterize clients with queues, requests, and
operations, and support undoable operations. Can be used in a combination
with queue to process commands together

Task Queue

@PostConstruct
public void startExecutionLoop() {
// Start a background thread to execute commands
new Thread(this::processCommands).start();
}

Benefit Description

Decouples invocation & execution Useful in background job systems

FIFO processing Ensures order of command execution

Supports async workloads Schedule, batch, or throttle command dispatching

3. Interator

a. The Iterator pattern allows you to traverse a collection (like a list, set, or
custom data structure) one element at a time, without knowing its internal
structure.

b. Iterating over services or tasks.

c. Streamlining batch operations.

Design Patterns Use Cases (Java And Spring) 6


d. Custom collection frameworks – when creating your own data structures.

e. Traversal abstraction – when you want to hide the internal structure (tree,
graph, etc.).

f. Multiple traversals – forward, reverse, or filtered iteration.

g. Undo functionality – iterate over a history stack.

h. Promotes encapsulation by hiding collection internals.

i. Allows multiple traversals.

j. Clean separation between collection and traversal logic.

4. Intepreter

a. The Interpreter Pattern defines a representation for a grammar and


provides an interpreter to deal with this grammar. It is used when we want
to evaluate language expressions.

b. Arithmetic expression evaluators ( 2 + 3 * 4 )

c. Rule engines (Json Rule Engine)

d. SQL parsing

e. Mini-language processing

f. Regex parsing

g. Search filters

5. Mediator

a. It allows you to encapsulate the interaction between objects (colleagues)


into a separate mediator object, improving code maintainability and
scalability.

b. The Mediator Design Pattern is a behavioral design pattern that


centralizes complex communications and control logic between related
objects in a system, promoting loose coupling by preventing objects from
referring to each other explicitly.

c. Chat System and Notification Channel

d. [Link]

Design Patterns Use Cases (Java And Spring) 7


6. Memento

a. Without exposing the object’s internal structure, you can save and restore
its state.

b. AL/ML rollbacks

✅ Summary Table
Domain Use Case

Text Editors Undo/Redo, Auto-save

Games Save/Load checkpoints

Web Forms Multi-step form navigation

Document Editors Version control, draft recovery

Business Apps Manual rollback of transactions

Config Tools Reset to defaults, profile switching

Workflow Engines Resume from saved workflow stage

FSMs Rollback state transitions

Simulators Snapshot and restore

AI/ML Training Save best model state during training

Use Case Example

Undo/Redo in editors Text editors (Notepad, Word, etc.)

Game Save/Load Saving a game state to resume later

Workflow snapshots Save intermediate workflow state for rollback

Versioning Object version history (drafts, edits)

Database transactions Rollback logic where a memento stores object state


(manual) before a transaction

7. Null State

a. The Null Object Design Pattern provides an object as a surrogate for the absence of a real object.
Instead of returning null, return a special object that implements the expected interface but does nothing (a
“do-nothing” implementation). This helps eliminate null checks and NullPointerExceptions.

b. Used to eliminate null checks


Design Patterns Use Cases (Java And Spring) 8
✅ Real-world Use Cases
Context Use Case

Repositories findById() returns NullObject if not found

Logging NoOpLogger avoids logging if disabled

Strategy Pattern Fallback behavior when no strategy matches

User Sessions Return a GuestUser instead of null session

Spring Boot Use Optional beans or empty object patterns

8. Observer

a. The Observer Design Pattern is a behavioral design pattern that defines a


one-to-many dependency between objects so that when one object (the
Subject) changes state, all its dependents (Observers) are notified and
updated automatically.

b. Email, SMS, or push notifications

Role Description

Subject Maintains a list of observers and notifies them

Observer Defines an updating interface

ConcreteSubject Stores state and notifies observers

ConcreteObserver Implements the observer interface

9. State

a. The State Design Pattern is a behavioral pattern that allows an object to


change its behavior when its internal state changes. It appears as if the
object changed its class.

b. ATM, Circuit Breaker, TCP/IP Machine, Game Dev

✅ Use Cases of State Design Pattern


Use Case Description

Workflow/Process engines e.g., Order states: Placed → Shipped → Delivered

Game development Player states: Idle, Running, Jumping, Attacking

Design Patterns Use Cases (Java And Spring) 9


UI components Button states: Enabled, Disabled, Hovered, Clicked

TCP connection states OPEN, LISTEN, CLOSED, SYN_SENT, etc.

ATM machine NoCard, HasCard, Authorized, OutOfService

10. Strategy

a. The Strategy Design Pattern is a behavioral pattern used to define a


family of algorithms, encapsulate each one, and make them
interchangeable at runtime. It enables selecting an algorithm's behavior at
runtime.

b. Define a set of algorithms, encapsulate each one, and make them


interchangeable. Strategy lets the algorithm vary independently from the
clients that use it.

c. Includes functions like execute, pay and compute, etc.

✅ Use Cases of Strategy Pattern


Use Case Example

Switch between different payment processors


Payment gateways
dynamically

Compression algorithms Support ZIP, RAR, TAR, etc.

Choose QuickSort, MergeSort, BubbleSort based on


Sorting strategies
dataset size

Validation strategies Apply different validation based on user type or context

Route selection GPS apps: fastest vs shortest vs scenic

Tax calculations Different tax rules for regions or countries

Authentication
mechanisms

11. Template

a. Define the skeleton of an algorithm in a method, deferring some steps to


subclasses. Template Method lets subclasses override certain steps of the
algorithm without changing its structure.

b. Workflows, code resuability and similar algorithms

Design Patterns Use Cases (Java And Spring) 10


Use Case Explanation

Frameworks where basic E.g., JUnit testing framework uses template


workflow is fixed methods for test lifecycle ( setUp , tearDown ).

Algorithms with invariant Sorting algorithms that share common parts but
structure but variable steps vary the pivot choice.

Code reuse with common Base classes define the skeleton, subclasses
algorithm parts override details.

Fixed steps with flexible sub-tasks inside a


Workflow engines and batch jobs
process.

Rendering lifecycle with customizable rendering


UI frameworks
steps.

Generic parse method with steps overridden by


Parsing and compiling
different language parsers.

12. Visitor

a. Separate an algorithm from the objects on which it operates. Visitor lets


you add further operations to objects without modifying them.

b. Shopping Cart and Document Processing

c. Imagine a document processing system with different types of


documents:

Invoice

Report

d. We want to:

Generate a summary for each document type.

Generate a detailed report for each document type.

Use Case Explanation

When you have complex object


hierarchies and want to perform
Complex object structures
operations across them without cluttering
the objects.

Design Patterns Use Cases (Java And Spring) 11


When you need to add new functionality
Adding operations without changing
frequently to unrelated classes but want
classes
to avoid modifying their code.

Visiting different types of nodes in


Abstract Syntax Trees (AST) for
Compilers and AST traversal
operations like code generation,
optimization, or type checking.

Performing different serialization


Serialization / Deserialization
strategies on diverse object types.

Rendering or processing different UI


UI rendering systems elements without embedding logic in the
elements themselves.

If multiple unrelated operations must be


performed on a fixed set of objects, visitor
Multiple unrelated operations
helps keep those operations clean and
separate.

Creational

1. Singleton

Where centralised access, a single point of control, resource sharing, or global


coordination is needed.

Java

public class Singleton {


private static Singleton instance;

private Singleton() {}

Design Patterns Use Cases (Java And Spring) 12


public static synchronized Singleton getInstance() { // Thread Safe
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

🧠 Summary: When to Use Singleton in System Design


System Component Role of Singleton

Config Loader Shared config for services

Token/Auth Manager Centralized authentication control

Cache Manager Single control of in-memory cache

Logging Service Centralized, thread-safe logging

Thread Pool Manager Controlled thread execution

Load Balancer Manager Central routing decision point

Metrics Exporter Avoid metric flooding

Broker / Coordinator Maintain consensus / topology state

Spring Boot

✅ [Link] – Singleton by Spring

package [Link];

import [Link];

@Service // This makes it a Spring-managed Singleton bean by default


public class LoggerService {

Design Patterns Use Cases (Java And Spring) 13


public LoggerService() {
[Link]("LoggerService instance created.");
}

public void log(String message) {


[Link]("[LOG] " + message);
}
}

✅ [Link]

package [Link];

import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/log")
public class LogController {

private final LoggerService loggerService;

@Autowired
public LogController(LoggerService loggerService) {
[Link] = loggerService;
}

@PostMapping
public String logMessage(@RequestParam String message) {
[Link](message);
return "Logged: " + message;

Design Patterns Use Cases (Java And Spring) 14


}
}

✅ Output on Server Start


Only one instance of LoggerService is created:

LoggerService instance created.

Even if you hit the /log?message=Hello endpoint multiple times, the same instance will
be reused.

2. Builder

When an object has many optional fields or parameters.

To avoid a telescoping constructor (many overloaded constructors) and


passing unwanted params during initialisation.

Java

public class User {


// Required fields
private final String firstName;
private final String lastName;

// Optional fields
private final int age;
private final String phone;
private final String address;

// Private constructor to enforce use of Builder


private User(UserBuilder builder) {
[Link] = [Link];

Design Patterns Use Cases (Java And Spring) 15


[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
}

public static class UserBuilder {


private final String firstName;
private final String lastName;

private int age;


private String phone;
private String address;

public UserBuilder(String firstName, String lastName) {


[Link] = firstName;
[Link] = lastName;
}

public UserBuilder age(int age) {


[Link] = age;
return this;
}

public UserBuilder phone(String phone) {


[Link] = phone;
return this;
}

public UserBuilder address(String address) {


[Link] = address;
return this;
}

public User build() {


return new User(this);

Design Patterns Use Cases (Java And Spring) 16


}
}

@Override
public String toString() {
return "User: " + firstName + " " + lastName + ", Age: " + age + ", Phone: " +
}
}

public class Main {


public static void main(String[] args) {
User user = new [Link]("Sai", "Ashish")
.age(23)
.phone("1234567890")
.address("Hyderabad")
.build();

[Link](user);
}
}

Spring Boot

package [Link];

import [Link];
import [Link];
import [Link];

@Getter
@ToString
@Builder
public class User {
private String firstName;
private String lastName;

Design Patterns Use Cases (Java And Spring) 17


private Integer age;
private String phone;
private String address;
}

package [Link];

import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/api/users")
public class UserController {

@PostMapping("/build")
public User buildUser(@RequestBody UserRequest req) {
return [Link]()
.firstName([Link]())
.lastName([Link]())
.age([Link]())
.phone([Link]())
.address([Link]())
.build();
}
}

3. Factory

A Factory Pattern defines an interface for creating an object


but lets subclasses decide which class to instantiate.

Java

Design Patterns Use Cases (Java And Spring) 18


🏭 Factory Pattern Using enum in Java

✅ 1. Define the Product Interface


public interface Notification {
void notifyUser();
}

✅ 2. Implement Concrete Notification Types


public class EmailNotification implements Notification {
public void notifyUser() {
[Link]("Sending an EMAIL notification");
}
}

public class SMSNotification implements Notification {


public void notifyUser() {
[Link]("Sending an SMS notification");
}
}

public class PushNotification implements Notification {


public void notifyUser() {
[Link]("Sending a PUSH notification");
}
}

✅ 3. Create Enum for Notification Types


public enum NotificationType {
EMAIL,

Design Patterns Use Cases (Java And Spring) 19


SMS,
PUSH
}

✅ 4. Factory Class with enum

public class NotificationFactory {

public static Notification createNotification(NotificationType type) {


return switch (type) {
case EMAIL -> new EmailNotification();
case SMS -> new SMSNotification();
case PUSH -> new PushNotification();
};
}
}

✅ 5. Client Usage
public class Main {
public static void main(String[] args) {
Notification notification = [Link](Notificati
[Link]);
[Link](); // Output: Sending an SMS notification
}
}

Spring Boot

🧱 1. Interface and Implementations


[Link]

Design Patterns Use Cases (Java And Spring) 20


package [Link];

public interface Notification {


String notifyUser();
}

[Link]

package [Link];

public class EmailNotification implements Notification {


@Override
public String notifyUser() {
return "Sending an EMAIL notification";
}
}

[Link]

package [Link];

public class SMSNotification implements Notification {


@Override
public String notifyUser() {
return "Sending an SMS notification";
}
}

[Link]

package [Link];

public class PushNotification implements Notification {


@Override

Design Patterns Use Cases (Java And Spring) 21


public String notifyUser() {
return "Sending a PUSH notification";
}
}

🧾 2. Enum
[Link]

package [Link];

public enum NotificationType {


EMAIL,
SMS,
PUSH
}

🏭 3. Factory Class
[Link]

package [Link];

import [Link].*;
import [Link];
import [Link];

@Component
public class NotificationFactory {

public Notification createNotification(NotificationType type) {


return switch (type) {
case EMAIL -> new EmailNotification();
case SMS -> new SMSNotification();

Design Patterns Use Cases (Java And Spring) 22


case PUSH -> new PushNotification();
};
}
}

🌐 4. Controller
[Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/api")
public class NotificationController {

private final NotificationFactory factory;

public NotificationController(NotificationFactory factory) {


[Link] = factory;
}

@PostMapping("/notify")
public String notifyUser(@RequestParam NotificationType type) {
Notification notification = [Link](type);
return [Link]();
}
}

🚀
Design Patterns Use Cases (Java And Spring) 23
🚀 5. Main Application
[Link]

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class NotificationFactoryApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

package [Link];

import [Link];
import [Link].slf4j.Slf4j;
import [Link];
import [Link];

import [Link];
import [Link];
import [Link];

@Service
@Slf4j
public class VehicleProvider {

Design Patterns Use Cases (Java And Spring) 24


private Map<VehicleType, Vehicle> vehicleMap;

@Autowired
public VehicleProvider(List<Vehicle> vehicleList){
vehicleMap = new HashMap<>();
for(Vehicle vehicle : vehicleList){
[Link]([Link](), vehicle);
}
}

public Vehicle getVehicle(VehicleType type){


return [Link](type);
}

package [Link];

public class VehicleFactory {

public static Vehicle create(String type, int wheel) {

switch (type) {
case "bike":
return new Bike(wheel);
case "car":
return new Car(wheel);
default:
[Link]("invalid type");
}

return null;

Design Patterns Use Cases (Java And Spring) 25


}

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@Service
@RequiredArgsConstructor
public class VehicleService {

private final VehicleProvider vehicleProvider;


private final VehicleBuilder vehicleBuilder;

public void process(){


Vehicle vehicle = [Link]([Link]);
[Link]("Vehicle's Wheel: " + [Link]());
[Link]([Link]());
}

public interface Vehicle<T extends VehicleContext> {


int getWheel();
VehicleType getType();
void process(T context);
}

@Service
@Slf4j
@RequiredArgsConstructor

Design Patterns Use Cases (Java And Spring) 26


public class Car implements Vehicle<CarContext> {

private static final VehicleType type = [Link];


private int wheel;

public Car(int wheel) {


[Link] = wheel;
}

@Override
public int getWheel() {
return wheel;
}

@Override
public VehicleType getType() {
return type;
}

@Override
public void process(CarContext context) {
[Link](type + " :process");
}
}

@Service
@Slf4j
@RequiredArgsConstructor
public class Bike implements Vehicle<BikeContext> {

private static final VehicleType type = [Link];


private int wheel;

public Bike(int wheel) {


[Link] = wheel;

Design Patterns Use Cases (Java And Spring) 27


}

@Override
public int getWheel() {
return wheel;
}

@Override
public VehicleType getType() {
return type;
}

@Override
public void process(BikeContext bikeContext) {
[Link](type + " : process");
}

public enum VehicleType {


BIKE,
CAR
}

@Component
public class VehicleBuilder {

private static final String bikeId = "1GNEK13ZX4R118208";

public BikeContext buildBikeContext(){


BikeContext bikeContext = new BikeContext();
[Link](bikeId);
return bikeContext;
}

Design Patterns Use Cases (Java And Spring) 28


}

@Data
public class BikeContext extends VehicleContext {
}

@Data
public class CarContext extends VehicleContext {
}

@Data
public class VehicleContext {
private String id;
}

Design Patterns Use Cases (Java And Spring) 29


Design Patterns Use Cases (Java And Spring) 30
Design Patterns Use Cases (Java And Spring) 31
Design Patterns Use Cases (Java And Spring) 32
Design Patterns Use Cases (Java And Spring) 33
Design Patterns Use Cases (Java And Spring) 34
Design Patterns Use Cases (Java And Spring) 35
Design Patterns Use Cases (Java And Spring) 36
Design Patterns Use Cases (Java And Spring) 37
4. Abstract Factory

It's essentially a factory of factories — it creates related objects grouped under a


common theme. Can be used in combination with template pattern to eliminate
duplicate code.

Design Patterns Use Cases (Java And Spring) 38


✅ 1. Abstract Products
// Abstract Product A
public interface Button {
void render();
}

// Abstract Product B
public interface Checkbox {
void render();
}

✅ 2. Concrete Products
// Windows
public class WindowsButton implements Button {
public void render() {
[Link]("Rendering Windows Button");
}
}

public class WindowsCheckbox implements Checkbox {


public void render() {
[Link]("Rendering Windows Checkbox");
}
}

// Mac
public class MacButton implements Button {
public void render() {
[Link]("Rendering Mac Button");
}
}

public class MacCheckbox implements Checkbox {

Design Patterns Use Cases (Java And Spring) 39


public void render() {
[Link]("Rendering Mac Checkbox");
}
}

✅ 3. Abstract Factory
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}

✅ 4. Concrete Factories
public class WindowsFactory implements GUIFactory {
public Button createButton() {
return new WindowsButton();
}

public Checkbox createCheckbox() {


return new WindowsCheckbox();
}
}

public class MacFactory implements GUIFactory {


public Button createButton() {
return new MacButton();
}

public Checkbox createCheckbox() {


return new MacCheckbox();
}
}

Design Patterns Use Cases (Java And Spring) 40


✅ 5. Client
public class Application {
private final Button button;
private final Checkbox checkbox;

public Application(GUIFactory factory) {


[Link] = [Link]();
[Link] = [Link]();
}

public void renderUI() {


[Link]();
[Link]();
}
}

✅ 6. Demo Main Class


public class Main {
public static void main(String[] args) {
GUIFactory factory = new WindowsFactory(); // or new MacFactory()
Application app = new Application(factory);
[Link]();
}
}

Abstract Factory + Template Pattern

Design Patterns Use Cases (Java And Spring) 41


Design Patterns Use Cases (Java And Spring) 42
Design Patterns Use Cases (Java And Spring) 43
Design Patterns Use Cases (Java And Spring) 44
Design Patterns Use Cases (Java And Spring) 45
Design Patterns Use Cases (Java And Spring) 46
Design Patterns Use Cases (Java And Spring) 47
Design Patterns Use Cases (Java And Spring) 48
Design Patterns Use Cases (Java And Spring) 49
5. Object Pool Pattern

🧠 Key Concepts
Expensive objects: These are objects that are costly to instantiate (e.g.,
database connections, thread pools, socket connections).

Pooling: Keeping a fixed number of objects and reusing them rather than
creating/destroying repeatedly.

Borrow & Return: Clients borrow objects from the pool and return them when
done.

Design Patterns Use Cases (Java And Spring) 50


✅ When to Use
Object creation is expensive (time/memory/resources).

You need a large number of short-lived objects.

You want to control the number of instances due to system resource limits
(e.g., threads, DB connections).

🧱 Structure
Client --> ObjectPool --> ReusableObject

🧪 Example in Java
class Reusable {
public void doWork() {
[Link]("Using reusable object: " + this);
}
}

class ObjectPool {
private List<Reusable> available = new ArrayList<>();
private List<Reusable> inUse = new ArrayList<>();

public synchronized Reusable acquire() {


if ([Link]()) {
[Link](new Reusable());
}
Reusable obj = [Link]([Link]() - 1);
[Link](obj);
return obj;
}

public synchronized void release(Reusable obj) {


[Link](obj);

Design Patterns Use Cases (Java And Spring) 51


[Link](obj);
}
}

Usage:

ObjectPool pool = new ObjectPool();

Reusable r1 = [Link]();
[Link]();

[Link](r1);

📦 Real-World Examples
Database Connection Pooling (e.g., HikariCP, Apache DBCP)

Thread Pool Executors in Java

TCP Socket Pools

Web Browser Tabs Pooling (in performance browsers)

🛠 Pros and Cons


Pros:

Reduces memory and CPU cost.

Controls number of instances (helps with scalability).

Performance boost with pre-initialized objects.

Cons:

Increased complexity in managing the pool.

Potential for memory leaks if objects are not returned.

Not suitable for objects that are cheap to create or heavily stateful.


Design Patterns Use Cases (Java And Spring) 52
✅ Example: Custom Object Pool in Spring Boot
🔧 Step 1: Create a Reusable Object
package [Link];

public class Reusable {


private final long id;

public Reusable(long id) {


[Link] = id;
}

public void use() {


[Link]("Using object with ID: " + id);
}

public long getId() {


return id;
}
}

⚙️ Step 2: Implement the Object Pool


package [Link];

import [Link];

import [Link].*;
import [Link];

@Component
public class ReusableObjectPool {
private final List<Reusable> available = new LinkedList<>();
private final Set<Reusable> inUse = new HashSet<>();

Design Patterns Use Cases (Java And Spring) 53


private final int MAX_POOL_SIZE = 5;
private final AtomicLong idGenerator = new AtomicLong(1);

public synchronized Reusable acquire() {


if (![Link]()) {
Reusable obj = [Link](0);
[Link](obj);
return obj;
}

if ([Link]() < MAX_POOL_SIZE) {


Reusable obj = new Reusable([Link]());
[Link](obj);
return obj;
}

throw new RuntimeException("All objects are in use.");


}

public synchronized void release(Reusable obj) {


if ([Link](obj)) {
[Link](obj);
}
}

public int availableCount() {


return [Link]();
}

public int inUseCount() {


return [Link]();
}
}

🧪 Step 3: Use It in a REST Controller


Design Patterns Use Cases (Java And Spring) 54
package [Link];

import [Link].*;

@RestController
@RequestMapping("/pool")
public class PoolController {

private final ReusableObjectPool objectPool;

public PoolController(ReusableObjectPool objectPool) {


[Link] = objectPool;
}

@GetMapping("/acquire")
public String acquire() {
try {
Reusable reusable = [Link]();
[Link]();
return "Acquired object with ID: " + [Link]();
} catch (RuntimeException e) {
return "Pool is full. Try again later.";
}
}

@PostMapping("/release/{id}")
public String release(@PathVariable long id) {
Reusable objToRelease = new Reusable(id);
[Link](objToRelease);
return "Released object with ID: " + id;
}

@GetMapping("/status")
public String status() {
return "Available: " + [Link]()

Design Patterns Use Cases (Java And Spring) 55


+ ", In Use: " + [Link]();
}
}

package [Link];

public class Connection {


private String id;

public Connection(String id) {


[Link] = id;
}

public void executeQuery(String query) {


[Link]("Executing query '" + query + "' on connection " + id);
}
}

package [Link];

import [Link];
import [Link];

import [Link];
import [Link];

@Component
public class ConnectionPoolManager {
private static final int MAX_POOL_SIZE = 5;

private Queue<Connection> pool;

public ConnectionPoolManager() {
pool = new ConcurrentLinkedQueue<>();

Design Patterns Use Cases (Java And Spring) 56


for (int i = 0; i < MAX_POOL_SIZE; i++) {
[Link](createConnection("Connection-" + (i + 1)));
}
}

public Connection borrowConnection() {


if ([Link]()) {
throw new RuntimeException("No available connections in the pool");
}
return [Link]();
}

public void returnConnection(Connection connection) {


if ([Link]() >= MAX_POOL_SIZE) {
throw new RuntimeException("Pool is full, cannot return connection");
}
[Link](connection);
}

private Connection createConnection(String id) {


return new Connection(id);
}
}

package [Link];

import [Link];
import [Link];

@Service
@RequiredArgsConstructor
public class DatabaseService {

private final ConnectionPoolManager connectionPoolManager;

Design Patterns Use Cases (Java And Spring) 57


public void executeQuery(String query) {
Connection connection = null;
try {
connection = [Link]();
[Link](query);
} finally {
if (connection != null) {
[Link](connection);
}
}
}
}

🧱 2. Create the Reusable Object ( ExpensiveWorker )

package [Link];

public class ExpensiveWorker {


private final long id;

public ExpensiveWorker(long id) {


[Link] = id;
simulateHeavyInitialization();
}

private void simulateHeavyInitialization() {


try {
[Link](500); // simulate expensive creation
} catch (InterruptedException ignored) {}
}

public void doWork() {


[Link]("Worker " + id + " is working...");
}

Design Patterns Use Cases (Java And Spring) 58


public long getId() {
return id;
}
}

⚙️ 3. Create the Object Pool ( WorkerPool )

package [Link];

import [Link];

import [Link].*;
import [Link];

@Component
public class WorkerPool {

private final List<ExpensiveWorker> available = new LinkedList<>();


private final Set<ExpensiveWorker> inUse = new HashSet<>();
private final int MAX_POOL_SIZE = 5;
private final AtomicLong idGenerator = new AtomicLong(1);

public synchronized ExpensiveWorker acquire() {


if (![Link]()) {
ExpensiveWorker worker = [Link](0);
[Link](worker);
return worker;
}

if ([Link]() < MAX_POOL_SIZE) {


ExpensiveWorker worker = new ExpensiveWorker([Link]
ncrement());
[Link](worker);
return worker;

Design Patterns Use Cases (Java And Spring) 59


}

throw new RuntimeException("All workers are currently in use.");


}

public synchronized void release(long id) {


Optional<ExpensiveWorker> workerOpt = [Link]()
.filter(w -> [Link]() == id)
.findFirst();

[Link](worker -> {
[Link](worker);
[Link](worker);
});
}

public synchronized int getAvailableCount() {


return [Link]();
}

public synchronized int getInUseCount() {


return [Link]();
}

public synchronized List<Long> getInUseIds() {


List<Long> ids = new ArrayList<>();
for (ExpensiveWorker w : inUse) {
[Link]([Link]());
}
return ids;
}

public synchronized List<Long> getAvailableIds() {


List<Long> ids = new ArrayList<>();
for (ExpensiveWorker w : available) {
[Link]([Link]());

Design Patterns Use Cases (Java And Spring) 60


}
return ids;
}
}

🌐 4. Expose REST API via PoolController

package [Link];

import [Link];
import [Link];
import [Link].*;

import [Link];
import [Link];

@RestController
@RequestMapping("/api/pool")
public class PoolController {

private final WorkerPool pool;

public PoolController(WorkerPool pool) {


[Link] = pool;
}

@GetMapping("/acquire")
public Map<String, Object> acquire() {
Map<String, Object> response = new HashMap<>();
try {
ExpensiveWorker worker = [Link]();
[Link]();
[Link]("message", "Worker acquired successfully");

Design Patterns Use Cases (Java And Spring) 61


[Link]("workerId", [Link]());
} catch (RuntimeException e) {
[Link]("error", [Link]());
}
return response;
}

@PostMapping("/release/{id}")
public Map<String, Object> release(@PathVariable long id) {
[Link](id);
return [Link]("message", "Worker " + id + " released.");
}

@GetMapping("/status")
public Map<String, Object> status() {
return [Link](
"availableCount", [Link](),
"inUseCount", [Link](),
"availableIds", [Link](),
"inUseIds", [Link]()
);
}
}

🚀 5. Application Entry Point


package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class ObjectPoolApplication {

Design Patterns Use Cases (Java And Spring) 62


public static void main(String[] args) {
[Link]([Link], args);
}
}

🧪 Test with cURL or Postman


Acquire a worker:

GET [Link]

Release a worker:

POST [Link]

View pool status:

GET [Link]

6. Prototype Pattern

✅ Real-World Analogy
Imagine you’re designing a document editor where users can duplicate shapes
(like a circle or rectangle) — instead of re-creating the shape every time, you can
clone an existing shape.

✅ Java Implementation of Prototype Pattern


1. Prototype Interface

Design Patterns Use Cases (Java And Spring) 63


public interface Prototype<T> {
T clone();
}

2. Concrete Class (e.g., Shape)

public class Shape implements Prototype<Shape> {


private String type;
private int x;
private int y;

public Shape(String type, int x, int y) {


[Link] = type;
this.x = x;
this.y = y;
}

@Override
public Shape clone() {
return new Shape(type, x, y); // deep copy
}

public void draw() {


[Link]("Drawing " + type + " at (" + x + ", " + y + ")");
}

public void setPosition(int x, int y) {


this.x = x;
this.y = y;
}
}

3. Client Usage

Design Patterns Use Cases (Java And Spring) 64


public class PrototypeDemo {
public static void main(String[] args) {
Shape original = new Shape("Circle", 10, 20);
[Link]();

Shape clone = [Link]();


[Link](30, 40);
[Link]();
}
}

🧪 Output
Drawing Circle at (10, 20)
Drawing Circle at (30, 40)

📦 Optional: Clone Using Cloneable Interface


Java also has the Cloneable interface and [Link]() method:

public class Shape implements Cloneable {


private String type;
private int x;

@Override
public Shape clone() {
try {
return (Shape) [Link]();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}

Design Patterns Use Cases (Java And Spring) 65


}
}

⚠️ Note: The Cloneable interface and [Link]() have limitations (e.g., shallow
copy), so many developers prefer implementing custom clone() logic.

✅ When to Use Prototype Pattern


When object creation is expensive (e.g., from DB or over the network)

When you want to avoid subclassing (unlike Factory pattern)

When you need many copies of similar objects

package [Link];

import [Link];
import [Link];

public class Vehicle implements Cloneable {

private List<String> vehicleList;

public Vehicle() {
[Link] = new ArrayList<>();
}

public Vehicle(List<String> list) {


[Link] = list;
}

public void insert() {


[Link]("BMW");
[Link]("Audi");
}

Design Patterns Use Cases (Java And Spring) 66


public List<String> getVehicleList() {
return [Link];
}

@Override
public Object clone() throws CloneNotSupportedException {
List<String> temp = new ArrayList<>();
for (String s : [Link]) {
[Link](s);
}
return new Vehicle(temp);
}

package [Link];

import [Link];

public class PrototypePattern {

public static void main(String[] args) throws CloneNotSupportedException {


Vehicle v = new Vehicle();
[Link]();
Vehicle v1 = (Vehicle) [Link]();
[Link]([Link]());
}

package [Link];

import [Link];

Design Patterns Use Cases (Java And Spring) 67


import [Link];

import [Link];

@Data
@AllArgsConstructor
public class Car extends AbstractVehicle {

private List<String> vehicleList;

@Override
public AbstractVehicle clone() {
return new Car(vehicleList);
}
}

package [Link];

import [Link];

import [Link];

@Data
public abstract class AbstractVehicle {
private List<String> vehicleList;
protected abstract AbstractVehicle clone();
}

🧠 Shallow Copy vs Deep Copy


Feature Shallow Copy Deep Copy

Copies entire object + objects


Definition Copies object references
inside (recursively)

Design Patterns Use Cases (Java And Spring) 68


Original and copy share same nested Original and copy are completely
Memory
object references independent

Slower (more memory and


Speed Faster (less memory work)
recursion)

When nested objects don’t need to


Use Case When full separation is needed
be duplicated

🔧 Java Example
Let's say we have:

class Address {
String city;

Address(String city) {
[Link] = city;
}
}

class Person {
String name;
Address address;

Person(String name, Address address) {


[Link] = name;
[Link] = address;
}
}

🧪 1. Shallow Copy
Person original = new Person("Sai", new Address("Bangalore"));
Person shallowCopy = new Person([Link], [Link]);

Design Patterns Use Cases (Java And Spring) 69


// Change in nested object affects both
[Link] = "Hyderabad";

[Link]([Link]); // 👉 Hyderabad (changed!)


👉 original and shallowCopy share the same Address object.

🧪 2. Deep Copy
Person original = new Person("Sai", new Address("Bangalore"));

// Deep copy: manually clone nested object


Person deepCopy = new Person([Link], new Address([Link].
city));

[Link] = "Hyderabad";

[Link]([Link]); // 👉 Bangalore (unchanged)


👉 Now [Link] is a new object, so changes don't affect the original.

🚀 Summary
Scenario Use Deep Copy?

Clone configs or DTOs safely ✅


Avoid memory overhead ❌
Copy primitives and shallow objects only ❌
Clone nested or mutable objects ✅

Behavioural

Design Patterns Use Cases (Java And Spring) 70


1. Adapter

✅ Use Case
Imagine you are integrating a third-party Media Player into your application, but
your app expects a different interface. Instead of rewriting existing code, you write
an adapter to connect both.

🧩 Structure
Target: The interface your client expects.

Adaptee: The existing interface you need to adapt.

Adapter: The class that implements Target and wraps an instance of Adaptee .

🧑‍💻 Example in Java


1. Target Interface

public interface MediaPlayer {


void play(String audioType, String fileName);
}

2. Adaptee Class

public class AdvancedMediaPlayer {


public void playVlc(String fileName) {
[Link]("Playing VLC file: " + fileName);
}

public void playMp4(String fileName) {


[Link]("Playing MP4 file: " + fileName);
}
}

Design Patterns Use Cases (Java And Spring) 71


3. Adapter Class

public class MediaAdapter implements MediaPlayer {


private AdvancedMediaPlayer advancedMediaPlayer;

public MediaAdapter(String audioType) {


advancedMediaPlayer = new AdvancedMediaPlayer();
}

@Override
public void play(String audioType, String fileName) {
if ("vlc".equalsIgnoreCase(audioType)) {
[Link](fileName);
} else if ("mp4".equalsIgnoreCase(audioType)) {
advancedMediaPlayer.playMp4(fileName);
} else {
[Link]("Invalid format: " + audioType);
}
}
}

4. Client Class

public class AudioPlayer implements MediaPlayer {


private MediaAdapter mediaAdapter;

@Override
public void play(String audioType, String fileName) {
if ("mp3".equalsIgnoreCase(audioType)) {
[Link]("Playing MP3 file: " + fileName);
} else if ("vlc".equalsIgnoreCase(audioType) || "mp4".equalsIgnoreCase
(audioType)) {
mediaAdapter = new MediaAdapter(audioType);
[Link](audioType, fileName);
} else {

Design Patterns Use Cases (Java And Spring) 72


[Link]("Unsupported format: " + audioType);
}
}
}

5. Main Method

public class AdapterPatternDemo {


public static void main(String[] args) {
MediaPlayer player = new AudioPlayer();
[Link]("mp3", "track.mp3");
[Link]("mp4", "movie.mp4");
[Link]("vlc", "[Link]");
[Link]("avi", "[Link]");
}
}

📦 Output
Playing MP3 file: track.mp3
Playing MP4 file: movie.mp4
Playing VLC file: [Link]
Unsupported format: avi

🎯 Use Cases
Scenario Description

✅ Legacy When working with legacy or third-party code that has a different
integration interface.

✅ Interface When two classes have incompatible interfaces, and you can't
mismatch change their source code.

Design Patterns Use Cases (Java And Spring) 73


✅ UI libraries Adapting custom UI components to fit third-party interfaces (e.g.,
adapting Swing components for a JavaFX app).

✅ API bridging Integrating APIs with differing method signatures or formats.

The Adapter Design Pattern is commonly used in Spring Boot projects when
integrating external systems, legacy APIs, or adapting interfaces to fit domain
models.

✅ Real-world Example in Spring Boot


Let’s say you have a Spring Boot app that consumes payment services from
multiple vendors (e.g., Stripe, Razorpay), but you want to expose a common
internal interface for your application to interact with any of them uniformly.

🔧BootStep-by-Step Adapter Implementation in Spring


1. Target Interface (Expected by your application)

public interface PaymentGateway {


void pay(double amount);
}

2. Adaptee Classes (Vendor SDKs or APIs)

Stripe SDK Simulation

public class StripePaymentSDK {


public void makeStripePayment(double amount) {
[Link]("Paid via Stripe: ₹" + amount);
}
}

Razorpay SDK Simulation

Design Patterns Use Cases (Java And Spring) 74


public class RazorpaySDK {
public void doRazorTransaction(double amountInPaise) {
[Link]("Paid via Razorpay: ₹" + amountInPaise / 100);
}
}

3. Adapters for Each SDK

Stripe Adapter

@Component("stripeAdapter")
public class StripeAdapter implements PaymentGateway {
private final StripePaymentSDK stripe = new StripePaymentSDK();

@Override
public void pay(double amount) {
[Link](amount);
}
}

Razorpay Adapter

@Component("razorpayAdapter")
public class RazorpayAdapter implements PaymentGateway {
private final RazorpaySDK razorpay = new RazorpaySDK();

@Override
public void pay(double amount) {
[Link](amount * 100); // Convert to paise
}
}

4. Service That Uses Adapter

Design Patterns Use Cases (Java And Spring) 75


@Service
public class PaymentService {

private final Map<String, PaymentGateway> gateways;

@Autowired
public PaymentService(Map<String, PaymentGateway> gateways) {
[Link] = gateways;
}

public void processPayment(String method, double amount) {


PaymentGateway gateway = [Link](method);
if (gateway != null) {
[Link](amount);
} else {
throw new IllegalArgumentException("Unsupported payment method: "
+ method);
}
}
}

@Component("stripeAdapter") and
@Component("razorpayAdapter") will inject the adapters using
a bean map.

5. Controller

@RestController
@RequestMapping("/api/payments")
public class PaymentController {

@Autowired
private PaymentService paymentService;

Design Patterns Use Cases (Java And Spring) 76


@PostMapping
public ResponseEntity<String> makePayment(
@RequestParam String method,
@RequestParam double amount) {
[Link](method, amount);
return [Link]("Payment of ₹" + amount + " done via " + meth
od);
}
}

🧠 Summary
Component Purpose
PaymentGateway Target interface used by Spring app

StripePaymentSDK , RazorpaySDK Adaptees (external/legacy services)

StripeAdapter , RazorpayAdapter Adapter classes that convert adaptee interface to target


PaymentService Uses the unified PaymentGateway interface
PaymentController Client that triggers the adapter-based logic

✅ Use Cases in Spring Boot


Integrating third-party SDKs or APIs.

Bridging legacy services with new Spring interfaces.

Switching between multiple implementations (e.g., database, caching layers).

Creating testable and loosely coupled service interfaces.

2. Bridge

Design Patterns Use Cases (Java And Spring) 77


The Bridge Design Pattern is a structural pattern used to decouple abstraction
from implementation, so that the two can vary independently.

🔧 Real-World Motivation
Imagine you're developing a drawing app where you have:

Different shapes (Circle, Square) — abstraction.

Multiple rendering engines (vector, raster) — implementation.

Instead of creating a class for every combination ( VectorCircle , RasterCircle , etc.), you
separate shape logic and rendering logic using the Bridge pattern.

🧱 Structure
Abstraction: High-level interface (e.g., Shape )

Refined Abstraction: Extends abstraction (e.g., Circle )

Implementor: Interface for implementation (e.g., Renderer )

Concrete Implementor: Implements Implementor (e.g., VectorRenderer ,


RasterRenderer )

1. Implementor Interface

public interface Renderer {


void render(String shapeType);
}

2. Concrete Implementors

public class VectorRenderer implements Renderer {


@Override
public void render(String shapeType) {
[Link]("Drawing " + shapeType + " as vectors.");

Design Patterns Use Cases (Java And Spring) 78


}
}

public class RasterRenderer implements Renderer {


@Override
public void render(String shapeType) {
[Link]("Drawing " + shapeType + " as pixels.");
}
}

3. Abstraction

public abstract class Shape {


protected Renderer renderer;

public Shape(Renderer renderer) {


[Link] = renderer;
}

public abstract void draw();


}

4. Refined Abstractions

public class Circle extends Shape {


public Circle(Renderer renderer) {
super(renderer);
}

@Override
public void draw() {
[Link]("Circle");
}
}

Design Patterns Use Cases (Java And Spring) 79


public class Square extends Shape {
public Square(Renderer renderer) {
super(renderer);
}

@Override
public void draw() {
[Link]("Square");
}
}

5. Demo

public class BridgePatternDemo {


public static void main(String[] args) {
Renderer vector = new VectorRenderer();
Renderer raster = new RasterRenderer();

Shape circle = new Circle(vector);


Shape square = new Square(raster);

[Link](); // Output: Drawing Circle as vectors.


[Link](); // Output: Drawing Square as pixels.
}
}

🧠 Use Cases of Bridge Pattern


Use Case Explanation

✅ UI frameworks Separating platform-independent UI logic from platform-specific


rendering (e.g., AWT vs Swing).

Design Patterns Use Cases (Java And Spring) 80


✅ Database drivers JDBC provides an abstraction over different databases. The
DriverManager bridges the JDBC API to specific DB drivers.

✅ File format A document can be exported as PDF, Word, HTML using different
exporters export strategies.

✅ Remote device A remote (abstraction) can operate TV, radio, projector


control (implementation).

✅ Messaging apps Send messages (text, image, video) via various channels (SMS,
Email, Push Notification).

✅ Game Game objects (e.g., units) can be rendered using different graphics
development engines (OpenGL, DirectX).

🔑 When to Use
You want to avoid a combinatorial explosion of classes.

You want to decouple abstraction from implementation for better flexibility.

You expect to change or extend both abstraction and implementation


independently.

Adapter pattern: You already have a StripeSDK and want to adapt it to your
internal interface PaymentProcessor .

Bridge pattern: You’re designing the system from scratch to support multiple
payment types (Stripe, Razorpay, PayPal) and multiple payment methods
(card, wallet, UPI) with separate hierarchies.

Implementing the Bridge Design Pattern in Spring Boot is useful when you want
to decouple abstraction from implementation, enabling them to vary
independently. This is especially helpful in systems that require flexible
architecture, such as notification systems, file exporters, or multi-database
systems.

✅ Real-World Example: Notification System


Design Patterns Use Cases (Java And Spring) 81
We want to support different notification types (e.g., alert, marketing) and
different delivery channels (e.g., email, SMS, push). Instead of creating a class
for each combination (like EmailAlertNotification , SMSMarketingNotification , etc.), we’ll bridge
the abstraction ( Notification ) from its implementation ( MessageSender ).

🧱 Structure
Abstraction: Notification

Refined Abstraction: AlertNotification , MarketingNotification

Implementor Interface: MessageSender

Concrete Implementors: EmailSender , SMSSender

✅ Implementation in Spring Boot


1. Implementor Interface

public interface MessageSender {


void sendMessage(String message);
}

2. Concrete Implementors

@Component("emailSender")
public class EmailSender implements MessageSender {
@Override
public void sendMessage(String message) {
[Link]("Sending Email: " + message);
}
}

@Component("smsSender")
public class SMSSender implements MessageSender {
@Override

Design Patterns Use Cases (Java And Spring) 82


public void sendMessage(String message) {
[Link]("Sending SMS: " + message);
}
}

3. Abstraction

public abstract class Notification {

protected final MessageSender messageSender;

public Notification(MessageSender messageSender) {


[Link] = messageSender;
}

public abstract void notifyUser(String message);


}

4. Refined Abstractions

public class AlertNotification extends Notification {


public AlertNotification(MessageSender messageSender) {
super(messageSender);
}

@Override
public void notifyUser(String message) {
[Link]("[ALERT] " + message);
}
}

public class MarketingNotification extends Notification {


public MarketingNotification(MessageSender messageSender) {
super(messageSender);

Design Patterns Use Cases (Java And Spring) 83


}

@Override
public void notifyUser(String message) {
[Link]("[MARKETING] " + message);
}
}

5. Bridge Config via Spring Boot

@Service
public class NotificationService {

private final Map<String, MessageSender> messageSenders;

@Autowired
public NotificationService(Map<String, MessageSender> messageSenders)
{
[Link] = messageSenders;
}

public void sendNotification(String type, String channel, String message) {


MessageSender sender = [Link](channel);
if (sender == null) {
throw new IllegalArgumentException("Unsupported channel: " + chann
el);
}

Notification notification;
switch (type) {
case "alert":
notification = new AlertNotification(sender);
break;
case "marketing":
notification = new MarketingNotification(sender);

Design Patterns Use Cases (Java And Spring) 84


break;
default:
throw new IllegalArgumentException("Unsupported type: " + type);
}

[Link](message);
}
}

6. REST Controller

@RestController
@RequestMapping("/notifications")
public class NotificationController {

private final NotificationService notificationService;

@Autowired
public NotificationController(NotificationService notificationService) {
[Link] = notificationService;
}

@PostMapping
public ResponseEntity<String> send(
@RequestParam String type,
@RequestParam String channel,
@RequestParam String message
){
[Link](type, channel, message);
return [Link]("Notification sent.");
}
}

📦
Design Patterns Use Cases (Java And Spring) 85
📦 Sample Request
POST /notifications?type=alert&channel=emailSender&message=Disk+Usage
+High

🧠 Use Cases of Bridge Pattern in Spring Boot


Use Case Description

🔔 Notification Decouple notification type from delivery mechanism


systems

📄 Report generation Report format (PDF, CSV) vs data source (SQL, NoSQL)

💬 Messaging systems Message type (text, image) vs delivery channel (email, push,
SMS)

🗃️ File storage Storage type (public, private) vs provider (S3, local, Azure)

🔌 Integration layers Business logic vs external APIs (bridge logic & adapter style)

3. Decorator (Wrapper)

The Decorator Design Pattern (also known as the Wrapper Pattern) is a structural
pattern used to dynamically add behavior or responsibilities to an object without
modifying its code. This is especially useful when you want to extend functionality
in a flexible and reusable way, without subclassing.

🧠 Core Concepts
Role Description
Component The original interface or abstract class (e.g., Notifier )
ConcreteComponent The original implementation (e.g., EmailNotifier )
Decorator The base class for decorators that implements Component
ConcreteDecorator Adds additional behavior (e.g., SMSDecorator , SlackDecorator )


Design Patterns Use Cases (Java And Spring) 86
✅ Java Example: Notification System with Decorators
We want to notify users via email, but also allow optional SMS and Slack
notifications without altering the original notifier.

1. Notifier Interface (Component)

public interface Notifier {


void send(String message);
}

2. EmailNotifier (ConcreteComponent)

public class EmailNotifier implements Notifier {


@Override
public void send(String message) {
[Link]("Sending Email: " + message);
}
}

3. NotifierDecorator (Base Decorator)

public abstract class NotifierDecorator implements Notifier {


protected Notifier wrappee;

public NotifierDecorator(Notifier notifier) {


[Link] = notifier;
}

@Override
public void send(String message) {
[Link](message);

Design Patterns Use Cases (Java And Spring) 87


}
}

4. SMSDecorator and SlackDecorator (Concrete Decorators)

public class SMSDecorator extends NotifierDecorator {


public SMSDecorator(Notifier notifier) {
super(notifier);
}

@Override
public void send(String message) {
[Link](message);
[Link]("Sending SMS: " + message);
}
}

public class SlackDecorator extends NotifierDecorator {


public SlackDecorator(Notifier notifier) {
super(notifier);
}

@Override
public void send(String message) {
[Link](message);
[Link]("Sending Slack Message: " + message);
}
}

5. Demo Usage

public class Main {


public static void main(String[] args) {
Notifier basicNotifier = new EmailNotifier();

Design Patterns Use Cases (Java And Spring) 88


// Wrap email with SMS
Notifier smsNotifier = new SMSDecorator(basicNotifier);

// Wrap SMS+Email with Slack


Notifier fullNotifier = new SlackDecorator(smsNotifier);

[Link]("Server is down!");
}
}

🔁 Output
Sending Email: Server is down!
Sending SMS: Server is down!
Sending Slack Message: Server is down!

🧠 Real-World Use Cases of Decorator Pattern


Use Case Description

Logging Add logging around service methods

Caching Wrap DAO or service methods with a caching layer

Validation Decorate data processing pipelines

Spring Boot Filters Servlet filters and interceptors act like decorators

Input/Output Streams BufferedInputStream , DataInputStream in Java I/O

🧩 Spring Boot Context Example (Optional)


In Spring, you can use the decorator pattern with beans using proxies. For
example:

@Component
@Primary

Design Patterns Use Cases (Java And Spring) 89


public class LoggingUserService implements UserService {
private final UserService delegate;

public LoggingUserService(@Qualifier("actualUserService") UserService d


elegate) {
[Link] = delegate;
}

@Override
public void createUser(String name) {
[Link]("Logging: Creating user " + name);
[Link](name);
}
}

✅ Summary
Decorator = Wrapper + Behavior

Promotes Open/Closed Principle: open for extension, closed for modification.

Great alternative to subclassing when multiple combinations of features are


needed.

In Spring Boot, the Decorator Design Pattern is often used to enhance or modify
the behavior of services without changing the original implementation. This is
typically done using delegation, bean overriding, and proxies.

✅BootReal-World Example: Decorator Pattern in Spring


🧩 Use Case: Logging + Notification Enhancer
We have a NotificationService that sends basic notifications. We want to add features
like logging and retry logic without changing its original code.

Design Patterns Use Cases (Java And Spring) 90


1. Base Interface

public interface NotificationService {


void send(String message);
}

2. Core Implementation

@Component("baseNotificationService")
public class EmailNotificationService implements NotificationService {
@Override
public void send(String message) {
[Link](" 📧 Sending Email: " + message);
}
}

3. Logging Decorator

@Component
@Primary // This will override the base implementation
public class LoggingNotificationDecorator implements NotificationService {

private final NotificationService delegate;

public LoggingNotificationDecorator(@Qualifier("baseNotificationService")
NotificationService delegate) {
[Link] = delegate;
}

@Override
public void send(String message) {
[Link](" 📝Logging: About to send message");
[Link](message);
[Link]("📝 Logging: Message sent");

Design Patterns Use Cases (Java And Spring) 91


}
}

4. Retry Decorator (Optional, Stackable)

@Component("retryingNotificationService")
public class RetryNotificationDecorator implements NotificationService {

private final NotificationService delegate;

public RetryNotificationDecorator(@Qualifier("loggingNotificationDecorato
r") NotificationService delegate) {
[Link] = delegate;
}

@Override
public void send(String message) {
int attempts = 0;
boolean success = false;

while (!success && attempts < 3) {


try {
[Link](message);
success = true;
} catch (Exception e) {
attempts++;
[Link](" ⚠️ Retry attempt " + attempts);
}
}

if (!success) {
[Link](" ❌ Failed to send message after 3 attempts");
}

Design Patterns Use Cases (Java And Spring) 92


}
}

You can wire this retry decorator manually into a config or use it directly.

5. Using the Decorated Bean

@RestController
@RequiredArgsConstructor
public class NotificationController {

private final NotificationService notificationService; // Spring injects the @P


rimary

@PostMapping("/send")
public ResponseEntity<String> sendNotification(@RequestParam String me
ssage) {
[Link](message);
return [Link]("Notification processed");
}
}

🧠 Notes
Concept Usage

Tells Spring to inject this bean when multiple beans implement an


@Primary
interface.
@Qualifier Lets you refer to a specific bean when injecting dependencies.
@Component Each decorator is a component and wired like a chain.
Bean Overriding You can create decorator chains via @Configuration too.

✅ Benefits
Follows Open/Closed Principle (no changes to the core class).

Design Patterns Use Cases (Java And Spring) 93


Easy to add or remove behavior like logging, caching, retry, etc.

Works beautifully with Spring DI and bean lifecycle.

🔄 Alternative: Decorator via Configuration


Instead of relying on @Component , you can configure your decorator chain:

@Configuration
public class NotificationConfig {

@Bean
public NotificationService notificationService() {
return new LoggingNotificationDecorator(
new RetryNotificationDecorator(
new EmailNotificationService()
)
);
}
}

💡 Common Spring Boot Use Cases


Decorator Use Case Example

Logging Log service method calls

Metrics Time a method and log to Prometheus

Security Add access control before calling real service

Retry Retry failed remote calls

Caching Cache method responses

Feature toggles Dynamically switch behavior using flags

4. Composite

Design Patterns Use Cases (Java And Spring) 94


The Composite Design Pattern is a structural pattern used to treat individual
objects and compositions of objects uniformly. It allows you to build tree-like
structures where nodes can be either leaf (basic objects) or composites
(containers of other objects).

🧠 Key Intent
"Compose objects into tree structures to represent part-whole
hierarchies. Composite lets clients treat individual objects and
compositions uniformly."

🧩 Real-World Analogy
Think of a file system:

A File is a leaf node.

A Directory can contain both files and subdirectories (which can contain more).

✅ Java Implementation: File System Example


1. Component Interface

public interface FileSystemComponent {


void showDetails(String indent);
}

2. Leaf: File

public class FileLeaf implements FileSystemComponent {


private final String name;

public FileLeaf(String name) {


[Link] = name;

Design Patterns Use Cases (Java And Spring) 95


}

@Override
public void showDetails(String indent) {
[Link](indent + "- File: " + name);
}
}

3. Composite: Directory

import [Link];
import [Link];

public class DirectoryComposite implements FileSystemComponent {


private final String name;
private final List<FileSystemComponent> children = new ArrayList<>();

public DirectoryComposite(String name) {


[Link] = name;
}

public void add(FileSystemComponent component) {


[Link](component);
}

public void remove(FileSystemComponent component) {


[Link](component);
}

@Override
public void showDetails(String indent) {
[Link](indent + "+ Directory: " + name);
for (FileSystemComponent component : children) {
[Link](indent + " ");
}

Design Patterns Use Cases (Java And Spring) 96


}
}

package [Link];

import [Link];
import [Link];

public class CompositeAccount extends Account {


private float totalBalance;
private List<Account> accountList = new ArrayList<Account>();

public float getBalance() {


totalBalance = 0;
for (Account f : accountList) {
totalBalance = totalBalance + [Link]();
}
return totalBalance;
}

public void addAccount(Account acc) {


[Link](acc);
}

public void removeAccount(Account acc) {


[Link](acc);
}
}

4. Usage

public class Main {


public static void main(String[] args) {
FileSystemComponent file1 = new FileLeaf("[Link]");

Design Patterns Use Cases (Java And Spring) 97


FileSystemComponent file2 = new FileLeaf("[Link]");
FileSystemComponent file3 = new FileLeaf("[Link]");

DirectoryComposite documents = new DirectoryComposite("Document


s");
[Link](file1);
[Link](file2);

DirectoryComposite work = new DirectoryComposite("Work");


[Link](file3);
[Link](documents);

[Link](""); // start with empty indent


}
}

🔄 Output
+ Directory: Work
- File: [Link]
+ Directory: Documents
- File: [Link]
- File: [Link]

✅ Use Cases of Composite Pattern


Domain Use Case

UI Toolkits Components like buttons, panels, and windows treated uniformly

File Systems Files and directories

XML/HTML Parsing Elements and nested elements

Drawing Apps Shapes vs Groups of Shapes

Menus MenuItem and Submenu hierarchy

Design Patterns Use Cases (Java And Spring) 98


Rule Engines Nested logical rules (AND/OR)

Product Bundles Products and product bundles (e.g., in e-commerce)

🤖 Benefits
Treat individual and composite objects uniformly.

Supports recursive structures naturally.

Makes adding new components easy.

⚠️ Drawbacks
Can make the design overly general.

Type-checking for leaves vs. composites might be necessary in stricter


environments.

🔷Departments)
Use Case Example: Organization Structure (Employees and

A Department can contain sub-departments or employees.

Employee is a leaf node.

Department is a composite.

This is a textbook example of the Composite Design Pattern.

✅ Final Structure
composite-pattern-springboot/

├── controller/
│ └── [Link]
├── model/
│ ├── [Link]

Design Patterns Use Cases (Java And Spring) 99


│ ├── [Link]
│ └── [Link]
├── service/
│ └── [Link]
├── [Link]

Step-by-Step Guide

📁 [Link] (Component)

package [Link];

public abstract class OrgComponent {


protected String name;

public OrgComponent(String name) {


[Link] = name;
}

public abstract void showDetails();


}

📁 [Link] (Leaf)

package [Link];

public class Employee extends OrgComponent {

private String role;

public Employee(String name, String role) {


super(name);
[Link] = role;

Design Patterns Use Cases (Java And Spring) 100


}

@Override
public void showDetails() {
[Link]("Employee: " + name + ", Role: " + role);
}
}

📁 [Link] (Composite)

package [Link];

import [Link];
import [Link];

public class Department extends OrgComponent {

private List<OrgComponent> components = new ArrayList<>();

public Department(String name) {


super(name);
}

public void addComponent(OrgComponent component) {


[Link](component);
}

public void removeComponent(OrgComponent component) {


[Link](component);
}

@Override
public void showDetails() {
[Link]("Department: " + name);
for (OrgComponent component : components) {

Design Patterns Use Cases (Java And Spring) 101


[Link]();
}
}
}

📁 [Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@Service
public class OrgService {

public OrgComponent createOrgStructure() {


Employee emp1 = new Employee("Alice", "Developer");
Employee emp2 = new Employee("Bob", "Tester");

Department devDept = new Department("Development");


[Link](emp1);
[Link](emp2);

Employee emp3 = new Employee("Carol", "HR");

Department hrDept = new Department("HR");


[Link](emp3);

Department headOffice = new Department("Head Office");


[Link](devDept);
[Link](hrDept);

return headOffice;

Design Patterns Use Cases (Java And Spring) 102


}
}

📁 [Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];

@RestController
public class OrgController {

private final OrgService orgService;

public OrgController(OrgService orgService) {


[Link] = orgService;
}

@GetMapping("/org")
public String getOrgStructure() {
OrgComponent root = [Link]();
[Link](); // You could alternatively return a custom DTO
return "Organization structure printed in logs.";
}
}

📁 [Link]

package [Link];

import [Link];

Design Patterns Use Cases (Java And Spring) 103


import [Link];

@SpringBootApplication
public class CompositePatternApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Output on calling /org endpoint:

Department: Head Office


Department: Development
Employee: Alice, Role: Developer
Employee: Bob, Role: Tester
Department: HR
Employee: Carol, Role: HR

🧠 Summary
Pattern Used: Composite Pattern

Leaf: Employee

Composite: Department

Client: OrgService and OrgController

Framework: Spring Boot

5. Filter (Criteria)

The Filter (Criteria) Design Pattern, a structural pattern (often treated as


behavioral as well), allows you to filter a set of objects using different criteria and
chaining them using logical operations such as AND, OR, NOT.

Design Patterns Use Cases (Java And Spring) 104


Step-by-Step Implementation in Java:

1. Create a Person class

public class Person {


private String name;
private String gender;
private String maritalStatus;

public Person(String name, String gender, String maritalStatus) {


[Link] = name;
[Link] = gender;
[Link] = maritalStatus;
}

public String getName() {


return name;
}

public String getGender() {


return gender;
}

public String getMaritalStatus() {


return maritalStatus;
}
}

2. Create a Criteria interface

import [Link];

public interface Criteria {

Design Patterns Use Cases (Java And Spring) 105


List<Person> meetCriteria(List<Person> persons);
}

3. Implement concrete criteria classes

import [Link];
import [Link];

public class CriteriaMale implements Criteria {


public List<Person> meetCriteria(List<Person> persons) {
List<Person> malePersons = new ArrayList<>();
for (Person person : persons) {
if ([Link]().equalsIgnoreCase("MALE")) {
[Link](person);
}
}
return malePersons;
}
}

public class CriteriaFemale implements Criteria {


public List<Person> meetCriteria(List<Person> persons) {
List<Person> femalePersons = new ArrayList<>();
for (Person person : persons) {
if ([Link]().equalsIgnoreCase("FEMALE")) {
[Link](person);
}
}
return femalePersons;
}
}

public class CriteriaSingle implements Criteria {


public List<Person> meetCriteria(List<Person> persons) {
List<Person> singlePersons = new ArrayList<>();

Design Patterns Use Cases (Java And Spring) 106


for (Person person : persons) {
if ([Link]().equalsIgnoreCase("SINGLE")) {
[Link](person);
}
}
return singlePersons;
}
}

4. Create combinational criteria classes

import [Link];
import [Link];

public class AndCriteria implements Criteria {


private Criteria criteria;
private Criteria otherCriteria;

public AndCriteria(Criteria criteria, Criteria otherCriteria) {


[Link] = criteria;
[Link] = otherCriteria;
}

public List<Person> meetCriteria(List<Person> persons) {


List<Person> firstCriteriaPersons = [Link](persons);
return [Link](firstCriteriaPersons);
}
}

public class OrCriteria implements Criteria {


private Criteria criteria;
private Criteria otherCriteria;

public OrCriteria(Criteria criteria, Criteria otherCriteria) {


[Link] = criteria;

Design Patterns Use Cases (Java And Spring) 107


[Link] = otherCriteria;
}

public List<Person> meetCriteria(List<Person> persons) {


List<Person> firstList = [Link](persons);
List<Person> secondList = [Link](persons);

for (Person person : secondList) {


if (![Link](person)) {
[Link](person);
}
}
return firstList;
}
}

5. Test the Filter Pattern

import [Link];
import [Link];

public class FilterPatternDemo {


public static void main(String[] args) {
List<Person> persons = [Link](
new Person("Robert", "Male", "Single"),
new Person("John", "Male", "Married"),
new Person("Laura", "Female", "Married"),
new Person("Diana", "Female", "Single"),
new Person("Mike", "Male", "Single"),
new Person("Bobby", "Male", "Single")
);

Criteria male = new CriteriaMale();


Criteria female = new CriteriaFemale();
Criteria single = new CriteriaSingle();

Design Patterns Use Cases (Java And Spring) 108


Criteria singleMale = new AndCriteria(single, male);
Criteria singleOrFemale = new OrCriteria(single, female);

[Link]("Males:");
printPersons([Link](persons));

[Link]("\nSingle Males:");
printPersons([Link](persons));

[Link]("\nSingle Or Females:");
printPersons([Link](persons));
}

public static void printPersons(List<Person> persons) {


for (Person person : persons) {
[Link]("Person: [ Name: " + [Link]()
+ ", Gender: " + [Link]()
+ ", Marital Status: " + [Link]() + " ]");
}
}
}

Output

Males:
Person: [ Name: Robert, Gender: Male, Marital Status: Single ]
Person: [ Name: John, Gender: Male, Marital Status: Married ]
Person: [ Name: Mike, Gender: Male, Marital Status: Single ]
Person: [ Name: Bobby, Gender: Male, Marital Status: Single ]

Single Males:
Person: [ Name: Robert, Gender: Male, Marital Status: Single ]
Person: [ Name: Mike, Gender: Male, Marital Status: Single ]
Person: [ Name: Bobby, Gender: Male, Marital Status: Single ]

Design Patterns Use Cases (Java And Spring) 109


Single Or Females:
Person: [ Name: Robert, Gender: Male, Marital Status: Single ]
Person: [ Name: Laura, Gender: Female, Marital Status: Married ]
Person: [ Name: Diana, Gender: Female, Marital Status: Single ]
Person: [ Name: Mike, Gender: Male, Marital Status: Single ]
Person: [ Name: Bobby, Gender: Male, Marital Status: Single ]

6. Proxy

The Proxy Design Pattern provides a surrogate or placeholder for another object
to control access to it. In Java, this is often used for:

Access control (e.g. protecting real objects)

Lazy initialization (e.g. expensive object creation)

Remote proxies (e.g. RMI)

Logging / auditing / caching

✅ Real-world Analogy
Think of a bank ATM as a proxy to your bank account — the ATM controls access
and enforces authentication before you interact with your actual account.

🔧 Structure
Subject (interface)

├── RealSubject (RealService)
└── Proxy (controls access to RealSubject)

🛠 Example: Internet Access Proxy


1. [Link] — Subject Interface

Design Patterns Use Cases (Java And Spring) 110


interface Internet {
void connectTo(String serverHost) throws Exception;
}

2. [Link] — Real Object

public class RealInternet implements Internet {


@Override
public void connectTo(String serverHost) {
[Link]("Connecting to " + serverHost);
}
}

3. [Link] — Proxy Implementation

import [Link];
import [Link];

public class ProxyInternet implements Internet {

private Internet realInternet = new RealInternet();


private static final List<String> bannedSites = [Link](
"[Link]", "[Link]", "[Link]"
);

@Override
public void connectTo(String serverHost) throws Exception {
if ([Link]([Link]())) {
throw new Exception("Access Denied to " + serverHost);
}
[Link](serverHost);

Design Patterns Use Cases (Java And Spring) 111


}
}

4. [Link] — Test Class

public class ProxyPatternDemo {


public static void main(String[] args) {
Internet internet = new ProxyInternet();

try {
[Link]("[Link]");
[Link]("[Link]");
} catch (Exception e) {
[Link]([Link]());
}
}
}

🧾 Output
Connecting to [Link]
Access Denied to [Link]

🔍 When to Use
Scenario Proxy Type

Restrict access Protection Proxy

Lazy load heavy objects Virtual Proxy

Add logs or cache Logging / Caching Proxy

Connect remote service Remote Proxy

🧠
Design Patterns Use Cases (Java And Spring) 112
🧠 Tip
Java's built-in [Link] and Spring AOP (like @Transactional ) also use
dynamic proxies.

✅ Use Case: Logging Access to a Service


We'll:

Create a VideoService that streams videos.

Wrap it with a LoggingProxyVideoService that logs each call.

Use Spring to inject the proxy instead of the real service.

🔧 Project Structure
proxy-pattern-springboot/
├── [Link]
├── service/
│ ├── [Link] (interface)
│ ├── [Link] (actual service)
│ └── [Link] (proxy)
└── controller/
└── [Link]

1. 🎬 [Link] (Interface)

package [Link];

public interface VideoService {


String streamVideo(String title);
}

📺
Design Patterns Use Cases (Java And Spring) 113
2. 📺 [Link] (Actual Service)

package [Link];

import [Link];

@Service("realVideoService")
public class RealVideoService implements VideoService {
@Override
public String streamVideo(String title) {
return "Streaming video: " + title;
}
}

3. 🔍 [Link] (Proxy)

package [Link];

import [Link];
import [Link];

@Service
public class LoggingProxyVideoService implements VideoService {

private final VideoService realService;

public LoggingProxyVideoService(@Qualifier("realVideoService") VideoSer


vice
realService) {
[Link] = realService;
}

@Override
public String streamVideo(String title) {

Design Patterns Use Cases (Java And Spring) 114


[Link]("[LOG] Requesting video: " + title);
String result = [Link](title);
[Link]("[LOG] Finished streaming: " + title);
return result;
}
}

4. 🎮 [Link]

package [Link];

import [Link];
import [Link].*;

@RestController
@RequestMapping("/video")
public class VideoController {

private final VideoService videoService;

public VideoController(VideoService videoService) {


[Link] = videoService;
}

@GetMapping("/watch")
public String watchVideo(@RequestParam String title) {
return [Link](title);
}
}

5. 🚀 [Link]

Design Patterns Use Cases (Java And Spring) 115


package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class ProxyPatternApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Run and Test


GET [Link]

Terminal Log:

[LOG] Requesting video: Inception


[LOG] Finished streaming: Inception

API Response:

Streaming video: Inception

🧠 Notes
We're injecting the proxy as the main bean ( LoggingProxyVideoService ) using
Spring's @Qualifier and constructor injection.

You can enhance the proxy to add auth, rate-limiting, caching, or circuit
breaking.

💡
Design Patterns Use Cases (Java And Spring) 116
💡 Alternatives in Spring
Feature Proxy Tool

AOP Logging @Aspect with @Around advice

Declarative Proxy Spring @Bean method returning a proxy

Circuit Breaking Resilience4j , Hystrix

Declarative REST Proxy FeignClient

✅ Use Case: Logging Access to a Service


We'll:

Create a VideoService that streams videos.

Wrap it with a LoggingProxyVideoService that logs each call.

Use Spring to inject the proxy instead of the real service.

🔧 Project Structure
proxy-pattern-springboot/
├── [Link]
├── service/
│ ├── [Link] (interface)
│ ├── [Link] (actual service)
│ └── [Link] (proxy)
└── controller/
└── [Link]

1. 🎬 [Link] (Interface)

package [Link];

public interface VideoService {

Design Patterns Use Cases (Java And Spring) 117


String streamVideo(String title);
}

2. 📺 [Link] (Actual Service)

java
CopyEdit
package [Link];

import [Link];

@Service("realVideoService")
public class RealVideoService implements VideoService {
@Override
public String streamVideo(String title) {
return "Streaming video: " + title;
}
}

3. 🔍 [Link] (Proxy)

java
CopyEdit
package [Link];

import [Link];
import [Link];

@Service
public class LoggingProxyVideoService implements VideoService {

private final VideoService realService;

Design Patterns Use Cases (Java And Spring) 118


public LoggingProxyVideoService(@Qualifier("realVideoService") VideoSer
vice realService) {
[Link] = realService;
}

@Override
public String streamVideo(String title) {
[Link]("[LOG] Requesting video: " + title);
String result = [Link](title);
[Link]("[LOG] Finished streaming: " + title);
return result;
}
}

4. 🎮 [Link]

java
CopyEdit
package [Link];

import [Link];
import [Link].*;

@RestController
@RequestMapping("/video")
public class VideoController {

private final VideoService videoService;

public VideoController(VideoService videoService) {


[Link] = videoService;
}

Design Patterns Use Cases (Java And Spring) 119


@GetMapping("/watch")
public String watchVideo(@RequestParam String title) {
return [Link](title);
}
}

5. 🚀 [Link]

java
CopyEdit
package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class ProxyPatternApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Run and Test


bash
CopyEdit
GET [Link]

Terminal Log:

Design Patterns Use Cases (Java And Spring) 120


bash
CopyEdit
[LOG] Requesting video: Inception
[LOG] Finished streaming: Inception

API Response:

css
CopyEdit
Streaming video: Inception

🧠 Notes
We're injecting the proxy as the main bean ( LoggingProxyVideoService ) using
Spring's @Qualifier and constructor injection.

You can enhance the proxy to add auth, rate-limiting, caching, or circuit
breaking.

💡 Alternatives in Spring
Feature Proxy Tool

AOP Logging @Aspect with @Around advice

Declarative Proxy Spring @Bean method returning a proxy

Circuit Breaking Resilience4j , Hystrix

Declarative REST Proxy FeignClient

Would you like to see an AOP-based proxy as well (even more idiomatic in
Spring)?

You said:

Design Patterns Use Cases (Java And Spring) 121


proxy design pattern using spring

ChatGPT said:
Here's how to implement the Proxy Design Pattern using Spring Framework
(without Spring Boot if preferred, or within Boot if needed), to intercept and
control access to a real service.

We'll show two ways:

1. Manual Proxy with @Component and @Qualifier (Classic proxy pattern).

2. Spring AOP-based Proxy (cleaner and idiomatic Spring way).

🔧 Use Case Example: Access Control to a Service


✅ Approach 1: Manual Proxy via @Component

📁 Structure
php
CopyEdit
[Link]
├── [Link] (interface)
├── [Link] (real object)
├── [Link] (proxy object)
└── [Link] (Spring config)

1. [Link] (Subject interface)

java
CopyEdit
public interface Internet {
void connectTo(String url) throws Exception;

Design Patterns Use Cases (Java And Spring) 122


}

2. [Link] (Real service)

java
CopyEdit
import [Link];

@Component("realInternet")
public class RealInternet implements Internet {
@Override
public void connectTo(String url) {
[Link]("Connected to " + url);
}
}

3. [Link] (Proxy class)

java
CopyEdit
import [Link];
import [Link];

import [Link];

@Component
public class ProxyInternet implements Internet {

private final Internet realInternet;


private final List<String> bannedSites = [Link]("[Link]", "[Link]
m");

Design Patterns Use Cases (Java And Spring) 123


public ProxyInternet(@Qualifier("realInternet") Internet realInternet) {
[Link] = realInternet;
}

@Override
public void connectTo(String url) throws Exception {
if ([Link]([Link]())) {
throw new Exception("Access Denied to " + url);
}
[Link](url);
}
}

4. [Link] (Spring app config for testing)

java
CopyEdit
import [Link]
ontext;
import [Link];
import [Link];

@Configuration
@ComponentScan("[Link]")
public class AppConfig {
public static void main(String[] args) {
var context = new AnnotationConfigApplicationContext([Link]
s);
Internet internet = [Link]([Link]);

try {
[Link]("[Link]");
[Link]("[Link]");
} catch (Exception e) {

Design Patterns Use Cases (Java And Spring) 124


[Link]([Link]());
}

[Link]();
}
}

✅ Output
bash
CopyEdit
Connected to [Link]
Access Denied to [Link]

✅largeApproach
apps)
2: Spring AOP-Based Proxy (Preferred in

🔍 Use Case: Log before and after a method runs.


1. Add Spring AOP Dependency
If you're using Maven:

xml
CopyEdit
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

Design Patterns Use Cases (Java And Spring) 125


2. Define a Service

java
CopyEdit
@Service
public class VideoService {
public void stream(String title) {
[Link]("Streaming video: " + title);
}
}

3. Define an Aspect (the proxy behavior)

java
CopyEdit
@Aspect
@Component
public class LoggingAspect {

@Before("execution(* [Link](..))")
public void logBefore(JoinPoint joinPoint) {
[Link]("[LOG] Starting: " + [Link]().getName
());
}

@After("execution(* [Link](..))")
public void logAfter(JoinPoint joinPoint) {
[Link]("[LOG] Finished: " + [Link]().getName
());
}
}

Design Patterns Use Cases (Java And Spring) 126


4. Call it from your main or controller

java
CopyEdit
@RestController
public class VideoController {
private final VideoService videoService;

public VideoController(VideoService videoService) {


[Link] = videoService;
}

@GetMapping("/watch")
public String watch(@RequestParam String title) {
[Link](title);
return "OK";
}
}

✅ Output
less
CopyEdit
[LOG] Starting: stream
Streaming video: Avatar
[LOG] Finished: stream

🔚 Summary
Approach Use Case

Manual Proxy Full control, low-level logic

Spring AOP Cross-cutting concerns (log, auth, perf)

Design Patterns Use Cases (Java And Spring) 127


9. Flyweight

The Flyweight Design Pattern is a structural pattern used to minimize memory


usage or computational expenses by sharing as much data as possible with
similar objects.

✅ Intent
Use sharing to support a large number of fine-grained objects
efficiently.

🔧 When to Use
You have many objects that consume a lot of memory.

Most object data is intrinsic (shared) and only a small part is extrinsic
(context-specific).

You want to reuse objects instead of creating new ones each time.

🧠 Key Concepts
Flyweight: The shared object.

Intrinsic State: Shared and independent of context.

Extrinsic State: Supplied by client, depends on context.

FlyweightFactory: Manages flyweight instances.

🧪 Real-World Use Cases


Use Case Description

Design Patterns Use Cases (Java And Spring) 128


Characters share font info (intrinsic), but position is
Text Editor (characters)
extrinsic.

Game Trees (chess, go) Reuse similar game pieces instead of creating new ones.

One icon object rendered in many places with different


Icons in UI
positions.

Reuse particle shape, size etc., change position/color


Particle systems
only.

Map rendering (e.g., Google


Reuse marker shapes/icons across locations.
Maps)

🛠️ Java Implementation
Scenario: Drawing multiple circles with only a few shared colors.

1. [Link] (Flyweight Interface)

public interface Shape {


void draw(int x, int y);
}

2. [Link] (Concrete Flyweight)

public class Circle implements Shape {


private final String color; // Intrinsic (shared)
private int x; // Extrinsic
private int y; // Extrinsic

public Circle(String color) {


[Link] = color;
}

@Override
public void draw(int x, int y) {

Design Patterns Use Cases (Java And Spring) 129


this.x = x;
this.y = y;
[Link]("Drawing %s circle at (%d, %d)%n", color, x, y);
}
}

3. [Link] (Flyweight Factory)

import [Link];
import [Link];

public class ShapeFactory {


private static final Map<String, Shape> circleMap = new HashMap<>();

public static Shape getCircle(String color) {


Circle circle = (Circle) [Link](color);

if (circle == null) {
circle = new Circle(color);
[Link](color, circle);
[Link]("Created circle of color: " + color);
}
return circle;
}
}

4. [Link] (Client Code)

public class FlyweightDemo {


public static void main(String[] args) {
String[] colors = { "Red", "Green", "Blue" };

for (int i = 0; i < 10; i++) {


String color = colors[i % [Link]];

Design Patterns Use Cases (Java And Spring) 130


Shape circle = [Link](color);
[Link]((int)([Link]() * 100), (int)([Link]() * 100));
}
}
}

✅ Output Example
Created circle of color: Red
Drawing Red circle at (22, 11)
Created circle of color: Green
Drawing Green circle at (55, 91)
Created circle of color: Blue
Drawing Blue circle at (72, 34)
Drawing Red circle at (99, 67)
...

💡 Summary
Element Role in Flyweight
Shape Flyweight interface
Circle Concrete Flyweight
ShapeFactory Creates/reuses Flyweights
x, y Extrinsic data
color Intrinsic (shared) data

🏁 Benefits
✅ Reduces memory usage
✅ Improves performance for large datasets
✅ Encourages sharing and reuse

Design Patterns Use Cases (Java And Spring) 131


✅ Goal
We'll simulate a UI icon system where the icon’s shape and type are intrinsic
(shared) and position is extrinsic (context-specific). We'll use Spring to manage
and share the flyweight beans.

📁 Project Structure
[Link]
├── [Link] // Flyweight interface
├── [Link] // Concrete Flyweight
├── [Link] // Flyweight factory using Spring
├── [Link] // Client
├── [Link] // Main class (SpringBootApplication)

🔧 Step-by-Step Spring Implementation


1. [Link] – Flyweight interface

public interface Icon {


void draw(int x, int y);
}

2. [Link] – Concrete Flyweight

import [Link];
import [Link];

@Component
@Scope("prototype") // Ensure different beans for different icons, if needed
public class SharedIcon implements Icon {

Design Patterns Use Cases (Java And Spring) 132


private String type; // Intrinsic state

public void setType(String type) {


[Link] = type;
}

@Override
public void draw(int x, int y) {
[Link]("Drawing '%s' icon at (%d, %d)%n", type, x, y);
}
}

3. [Link] – Factory using Spring Context

import [Link];
import [Link];
import [Link];

import [Link];
import [Link];

@Component
public class IconFactory {

@Autowired
private ApplicationContext context;

private final Map<String, Icon> cache = new HashMap<>();

public Icon getIcon(String type) {


if (![Link](type)) {
SharedIcon icon = [Link]([Link]);
[Link](type);
[Link](type, icon);

Design Patterns Use Cases (Java And Spring) 133


[Link]("Created new icon of type: " + type);
}
return [Link](type);
}
}

4. [Link] – Client using Flyweights

java
CopyEdit
import [Link];
import [Link];

@Service
public class IconUsageService {

@Autowired
private IconFactory iconFactory;

public void drawUI() {


String[] types = {"folder", "file", "trash"};

for (int i = 0; i < 10; i++) {


String type = types[i % [Link]];
Icon icon = [Link](type);
[Link](i * 10, i * 5); // x, y are extrinsic
}
}
}

5. [Link] – Main Spring Boot App

import [Link];
import [Link];

Design Patterns Use Cases (Java And Spring) 134


import [Link];

@SpringBootApplication
public class FlyweightApp implements CommandLineRunner {

private final IconUsageService usageService;

public FlyweightApp(IconUsageService usageService) {


[Link] = usageService;
}

public static void main(String[] args) {


[Link]([Link], args);
}

@Override
public void run(String... args) {
[Link]();
}
}

✅ Output
Created new icon of type: folder
Drawing 'folder' icon at (0, 0)
Created new icon of type: file
Drawing 'file' icon at (10, 5)
Created new icon of type: trash
Drawing 'trash' icon at (20, 10)
Drawing 'folder' icon at (30, 15)
Drawing 'file' icon at (40, 20)
...

📚
Design Patterns Use Cases (Java And Spring) 135
📚 Summary
Component Role
Icon Flyweight interface
SharedIcon Intrinsic state (shared icon)
IconFactory Flyweight manager
IconUsageService Client using icons

Spring Context Manages bean creation

✅ Benefits of Using Spring


✅ Easy caching & management
✅ Leverage dependency injection
✅ Cleaner separation of concerns
✅ Prototype scope for fine-grained control

✅ Goal
We'll simulate a UI icon system where the icon’s shape and type are intrinsic
(shared) and position is extrinsic (context-specific). We'll use Spring to manage
and share the flyweight beans.

📁 Project Structure
[Link]
├── [Link] // Flyweight interface
├── [Link] // Concrete Flyweight
├── [Link] // Flyweight factory using Spring
├── [Link] // Client
├── [Link] // Main class (SpringBootApplication)

Design Patterns Use Cases (Java And Spring) 136


🔧 Step-by-Step Spring Implementation
1. [Link] – Flyweight interface

public interface Icon {


void draw(int x, int y);
}

2. [Link] – Concrete Flyweight

import [Link];
import [Link];

@Component
@Scope("prototype") // Ensure different beans for different icons, if needed
public class SharedIcon implements Icon {

private String type; // Intrinsic state

public void setType(String type) {


[Link] = type;
}

@Override
public void draw(int x, int y) {
[Link]("Drawing '%s' icon at (%d, %d)%n", type, x, y);
}
}

3. [Link] – Factory using Spring Context

Design Patterns Use Cases (Java And Spring) 137


import [Link];
import [Link];
import [Link];

import [Link];
import [Link];

@Component
public class IconFactory {

@Autowired
private ApplicationContext context;

private final Map<String, Icon> cache = new HashMap<>();

public Icon getIcon(String type) {


if (![Link](type)) {
SharedIcon icon = [Link]([Link]);
[Link](type);
[Link](type, icon);
[Link]("Created new icon of type: " + type);
}
return [Link](type);
}
}

4. [Link] – Client using Flyweights

import [Link];
import [Link];

@Service
public class IconUsageService {

Design Patterns Use Cases (Java And Spring) 138


@Autowired
private IconFactory iconFactory;

public void drawUI() {


String[] types = {"folder", "file", "trash"};

for (int i = 0; i < 10; i++) {


String type = types[i % [Link]];
Icon icon = [Link](type);
[Link](i * 10, i * 5); // x, y are extrinsic
}
}
}

5. [Link] – Main Spring Boot App

import [Link];
import [Link];
import [Link];

@SpringBootApplication
public class FlyweightApp implements CommandLineRunner {

private final IconUsageService usageService;

public FlyweightApp(IconUsageService usageService) {


[Link] = usageService;
}

public static void main(String[] args) {


[Link]([Link], args);
}

@Override
public void run(String... args) {

Design Patterns Use Cases (Java And Spring) 139


[Link]();
}
}

✅ Output
Created new icon of type: folder
Drawing 'folder' icon at (0, 0)
Created new icon of type: file
Drawing 'file' icon at (10, 5)
Created new icon of type: trash
Drawing 'trash' icon at (20, 10)
Drawing 'folder' icon at (30, 15)
Drawing 'file' icon at (40, 20)
...

📚 Summary
Component Role
Icon Flyweight interface
SharedIcon Intrinsic state (shared icon)
IconFactory Flyweight manager
IconUsageService Client using icons

Spring Context Manages bean creation

✅ Benefits of Using Spring


✅ Easy caching & management
✅ Leverage dependency injection
✅ Cleaner separation of concerns
✅ Prototype scope for fine-grained control

Design Patterns Use Cases (Java And Spring) 140


🔧 Enhancement Plan
We'll modify IconFactory to include:

A createdCount to track newly created icons.

A reusedCount to track reused icons.

A new method printStats() to display runtime metrics.

✅ Updated [Link]

import [Link];
import [Link];
import [Link];

import [Link];
import [Link];

@Component
public class IconFactory {

@Autowired
private ApplicationContext context;

private final Map<String, Icon> cache = new HashMap<>();


private int createdCount = 0;
private int reusedCount = 0;

public Icon getIcon(String type) {


if (![Link](type)) {
SharedIcon icon = [Link]([Link]);
[Link](type);
[Link](type, icon);

Design Patterns Use Cases (Java And Spring) 141


createdCount++;
[Link]("Created new icon of type: " + type);
} else {
reusedCount++;
[Link]("Reused icon of type: " + type);
}
return [Link](type);
}

public void printStats() {


[Link]("\n--- IconFactory Runtime Stats ---");
[Link]("Total icon types created: " + createdCount);
[Link]("Total icon types reused: " + reusedCount);
[Link]("Cache size (distinct icons): " + [Link]());
}
}

✅ Updated [Link]
We'll add a call to printStats() at the end of drawUI() .

import [Link];
import [Link];

@Service
public class IconUsageService {

@Autowired
private IconFactory iconFactory;

public void drawUI() {


String[] types = {"folder", "file", "trash"};

for (int i = 0; i < 10; i++) {


String type = types[i % [Link]];

Design Patterns Use Cases (Java And Spring) 142


Icon icon = [Link](type);
[Link](i * 10, i * 5);
}

// Print stats after rendering


[Link]();
}
}

✅ Sample Output
Created new icon of type: folder
Drawing 'folder' icon at (0, 0)
Created new icon of type: file
Drawing 'file' icon at (10, 5)
Created new icon of type: trash
Drawing 'trash' icon at (20, 10)
Reused icon of type: folder
Drawing 'folder' icon at (30, 15)
...

--- IconFactory Runtime Stats ---


Total icon types created: 3
Total icon types reused: 7
Cache size (distinct icons): 3

✅ Summary of What We Added


Metric Purpose
createdCount Count of distinct icons created
reusedCount Count of times cache was hit
printStats() Shows the runtime metrics

Design Patterns Use Cases (Java And Spring) 143


Would you like to expose this as a REST API endpoint (e.g., /icons/stats ) or integrate
it with Spring Actuator metrics?

✅ Goal
Create a REST controller with:

GET /icons/stats → returns icon creation and reuse metrics as JSON.

Optionally: expose GET /icons/draw-ui to simulate drawing and trigger stats.

🔧 Step-by-Step Implementation
✅ 1. Add [Link] DTO

public class IconStatsResponse {


private int createdCount;
private int reusedCount;
private int cacheSize;

public IconStatsResponse(int createdCount, int reusedCount, int cacheSize)


{
[Link] = createdCount;
[Link] = reusedCount;
[Link] = cacheSize;
}

public int getCreatedCount() {


return createdCount;
}

public int getReusedCount() {


return reusedCount;

Design Patterns Use Cases (Java And Spring) 144


}

public int getCacheSize() {


return cacheSize;
}
}

✅ 2. Modify [Link] to expose metric values

public int getCreatedCount() {


return createdCount;
}

public int getReusedCount() {


return reusedCount;
}

public int getCacheSize() {


return [Link]();
}

✅ 3. Create [Link]

import [Link];
import [Link].*;

@RestController
@RequestMapping("/icons")
public class IconController {

@Autowired
private IconFactory iconFactory;

@Autowired

Design Patterns Use Cases (Java And Spring) 145


private IconUsageService iconUsageService;

@GetMapping("/stats")
public IconStatsResponse getStats() {
return new IconStatsResponse(
[Link](),
[Link](),
[Link]()
);
}

@PostMapping("/draw-ui")
public String drawUI() {
[Link]();
return "UI drawn with icons. Check /icons/stats for metrics.";
}
}

🧪 Example Requests
➤ Simulate Drawing
POST /icons/draw-ui

Response:

UI drawn with icons. Check /icons/stats for metrics.

➤ Get Runtime Stats


GET /icons/stats

Response:

Design Patterns Use Cases (Java And Spring) 146


{
"createdCount": 3,
"reusedCount": 7,
"cacheSize": 3
}

✅ Optional Enhancements
Feature Add-on

Use Spring Actuator /actuator/metrics

Log to a DB or Grafana Metrics exporter

Reset counts (for tests) Add @PostMapping("/reset")

Auto cache expiry Use @Cacheable with TTL

10. Facade

🧩 What is the Facade Pattern?


The Facade pattern provides a simplified interface to a complex subsystem. It's
useful when:

You want to hide system complexity from the client.

You want to provide a unified interface to multiple components.

✅ Real-Life Example: Online Order System


Subsystems:

InventoryService – checks product availability

PaymentService – processes payments

ShippingService – handles delivery

The Facade: OrderFacade coordinates all of them.

Design Patterns Use Cases (Java And Spring) 147


📁 Project Structure
src/
├── controller/
│ └── [Link]
├── facade/
│ └── [Link]
├── services/
│ ├── [Link]
│ ├── [Link]
│ └── [Link]

✅ 1. Create Subsystems (Services)


[Link]

package [Link];

import [Link];

@Service
public class InventoryService {
public boolean checkStock(String productId) {
[Link]("Checking stock for: " + productId);
return true; // assume in stock
}
}

[Link]

package [Link];

import [Link];

Design Patterns Use Cases (Java And Spring) 148


@Service
public class PaymentService {
public boolean processPayment(String userId, double amount) {
[Link]("Processing payment of $" + amount + " for user: " +
userId);
return true; // assume payment successful
}
}

[Link]

package [Link];

import [Link];

@Service
public class ShippingService {
public void shipProduct(String productId, String userId) {
[Link]("Shipping " + productId + " to user: " + userId);
}
}

✅ 2. Create the Facade


[Link]

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

Design Patterns Use Cases (Java And Spring) 149


@Component
public class OrderFacade {

@Autowired
private InventoryService inventoryService;

@Autowired
private PaymentService paymentService;

@Autowired
private ShippingService shippingService;

public String placeOrder(String productId, String userId, double amount) {


if (![Link](productId)) {
return "Product out of stock!";
}

if (![Link](userId, amount)) {
return "Payment failed!";
}

[Link](productId, userId);
return "Order placed successfully!";
}
}

✅ 3. Create REST Controller


[Link]

package [Link];

import [Link];
import [Link];
import [Link].*;

Design Patterns Use Cases (Java And Spring) 150


@RestController
@RequestMapping("/orders")
public class OrderController {

@Autowired
private OrderFacade orderFacade;

@PostMapping("/place")
public String placeOrder(@RequestParam String productId,
@RequestParam String userId,
@RequestParam double amount) {
return [Link](productId, userId, amount);
}
}

🧪 Test via Postman or cURL


POST [Link]
=50

Output:

Checking stock for: 123


Processing payment of $50.0 for user: abc
Shipping 123 to user: abc
Order placed successfully!

✅ Summary
Layer Role
OrderController Accepts request from user
OrderFacade Simplifies interactions with subsystems

Design Patterns Use Cases (Java And Spring) 151


Services Do the actual work (inventory, payment, shipping)

🎯 Use Case: Online Order System


You have subsystems:

InventoryService – checks if product is in stock

PaymentService – handles payment

ShippingService – manages delivery

The OrderFacade class simplifies interaction with all these services.

✅ 1. Define the Subsystems


[Link]

public class InventoryService {


public boolean checkStock(String productId) {
[Link]("Checking stock for: " + productId);
return true; // Always available for demo
}
}

[Link]

public class PaymentService {


public boolean processPayment(String userId, double amount) {
[Link]("Processing payment of $" + amount + " for user: " +
userId);
return true; // Payment always succeeds

Design Patterns Use Cases (Java And Spring) 152


}
}

[Link]

public class ShippingService {


public void shipProduct(String productId, String userId) {
[Link]("Shipping product " + productId + " to user: " + userI
d);
}
}

✅ 2. Create the Facade


[Link]

public class OrderFacade {

private InventoryService inventoryService;


private PaymentService paymentService;
private ShippingService shippingService;

public OrderFacade() {
[Link] = new InventoryService();
[Link] = new PaymentService();
[Link] = new ShippingService();
}

public String placeOrder(String productId, String userId, double amount) {


if (![Link](productId)) {
return "Order failed: Product out of stock!";
}

if (![Link](userId, amount)) {

Design Patterns Use Cases (Java And Spring) 153


return "Order failed: Payment failed!";
}

[Link](productId, userId);
return "Order placed successfully!";
}
}

✅ 3. Main Method to Run It


[Link]

public class Main {


public static void main(String[] args) {
OrderFacade orderFacade = new OrderFacade();

String result = [Link]("P123", "U456", 99.99);


[Link](result);
}
}

✅ Output
Cecking stock for: P123
Processing payment of $99.99 for user: U456
Shipping product P123 to user: U456
Order placed successfully!

✅ Summary
Class Responsibility
InventoryService Checks product availability

Design Patterns Use Cases (Java And Spring) 154


PaymentService Handles user payment
ShippingService Ships the product
OrderFacade Combines above steps via one method
Main Uses the Facade

Structural

1. Chain Of Responsibility

The Chain of Responsibility (CoR) design pattern allows you to pass a request
along a chain of handlers until one of them handles it. It’s useful when multiple
objects can handle a request and you want to decouple the sender and receiver.

✅ Real-World Use Case


Logging System – where logs are passed from DEBUG → INFO → ERROR , and each
level decides whether to process or pass it along.

Other use cases:

Event processing pipelines

Authentication filters

Form validation chains

Middleware in web frameworks

✅ Goal: Logging Handler Example in Java


Chain:
DebugLogger → InfoLogger → ErrorLogger

Each logger decides if it can handle the log level; if not, it passes it forward.

📁
Design Patterns Use Cases (Java And Spring) 155
📁 File Structure
src/
├── [Link] (abstract handler)
├── [Link] (concrete handler)
├── [Link]
├── [Link]
└── [Link] (to run the chain)

✅ 1. Abstract Logger (Handler)


public abstract class Logger {
public static final int DEBUG = 1;
public static final int INFO = 2;
public static final int ERROR = 3;

protected int level;


protected Logger nextLogger;

public void setNextLogger(Logger nextLogger) {


[Link] = nextLogger;
}

public void logMessage(int level, String message) {


if ([Link] <= level) {
write(message);
}
if (nextLogger != null) {
[Link](level, message);
}
}

Design Patterns Use Cases (Java And Spring) 156


protected abstract void write(String message);
}

✅ 2. Concrete Loggers
[Link]

public class DebugLogger extends Logger {


public DebugLogger() {
[Link] = DEBUG;
}

@Override
protected void write(String message) {
[Link]("[DEBUG]: " + message);
}
}

[Link]

public class InfoLogger extends Logger {


public InfoLogger() {
[Link] = INFO;
}

@Override
protected void write(String message) {
[Link]("[INFO]: " + message);
}
}

[Link]

Design Patterns Use Cases (Java And Spring) 157


public class ErrorLogger extends Logger {
public ErrorLogger() {
[Link] = ERROR;
}

@Override
protected void write(String message) {
[Link]("[ERROR]: " + message);
}
}

✅ 3. Run the Chain


[Link]

public class Main {


private static Logger getLoggerChain() {
Logger errorLogger = new ErrorLogger();
Logger infoLogger = new InfoLogger();
Logger debugLogger = new DebugLogger();

[Link](infoLogger);
[Link](errorLogger);

return debugLogger;
}

public static void main(String[] args) {


Logger loggerChain = getLoggerChain();

[Link]([Link], "Debugging application.");


[Link]([Link], "Information message.");
[Link]([Link], "An error occurred!");

Design Patterns Use Cases (Java And Spring) 158


}
}

✅ Output
[DEBUG]: Debugging application.
[INFO]: Information message.
[ERROR]: An error occurred!

Each message is passed through the chain; each handler decides whether to act.

🧠 Summary
Concept Description

Pattern Chain of Responsibility

Purpose Decouple sender and receivers

Key Benefit Flexibility in processing, avoids tight coupling

Real Uses Loggers, Authentication filters, Validation pipelines

The Chain of Responsibility (CoR) design pattern allows you to pass a request
along a chain of handlers until one of them handles it. It’s useful when multiple
objects can handle a request and you want to decouple the sender and receiver.

✅ Real-World Use Case


Logging System – where logs are passed from DEBUG → INFO → ERROR , and each
level decides whether to process or pass it along.

Other use cases:

Event processing pipelines

Authentication filters

Design Patterns Use Cases (Java And Spring) 159


Form validation chains

Middleware in web frameworks

✅ Goal: Logging Handler Example in Java


Chain:
DebugLogger → InfoLogger → ErrorLogger

Each logger decides if it can handle the log level; if not, it passes it forward.

📁 File Structure
src/
├── [Link] (abstract handler)
├── [Link] (concrete handler)
├── [Link]
├── [Link]
└── [Link] (to run the chain)

✅ 1. Abstract Logger (Handler)


public abstract class Logger {
public static final int DEBUG = 1;
public static final int INFO = 2;
public static final int ERROR = 3;

protected int level;


protected Logger nextLogger;

public void setNextLogger(Logger nextLogger) {


[Link] = nextLogger;
}

Design Patterns Use Cases (Java And Spring) 160


public void logMessage(int level, String message) {
if ([Link] <= level) {
write(message);
}
if (nextLogger != null) {
[Link](level, message);
}
}

protected abstract void write(String message);


}

✅ 2. Concrete Loggers
[Link]

public class DebugLogger extends Logger {


public DebugLogger() {
[Link] = DEBUG;
}

@Override
protected void write(String message) {
[Link]("[DEBUG]: " + message);
}
}

[Link]

java
CopyEdit
public class InfoLogger extends Logger {
public InfoLogger() {
[Link] = INFO;

Design Patterns Use Cases (Java And Spring) 161


}

@Override
protected void write(String message) {
[Link]("[INFO]: " + message);
}
}

[Link]

java
CopyEdit
public class ErrorLogger extends Logger {
public ErrorLogger() {
[Link] = ERROR;
}

@Override
protected void write(String message) {
[Link]("[ERROR]: " + message);
}
}

✅ 3. Run the Chain


[Link]

java
CopyEdit
public class Main {
private static Logger getLoggerChain() {
Logger errorLogger = new ErrorLogger();

Design Patterns Use Cases (Java And Spring) 162


Logger infoLogger = new InfoLogger();
Logger debugLogger = new DebugLogger();

[Link](infoLogger);
[Link](errorLogger);

return debugLogger;
}

public static void main(String[] args) {


Logger loggerChain = getLoggerChain();

[Link]([Link], "Debugging application.");


[Link]([Link], "Information message.");
[Link]([Link], "An error occurred!");
}
}

✅ Output
markdown
CopyEdit
[DEBUG]: Debugging application.
[INFO]: Information message.
[ERROR]: An error occurred!

Each message is passed through the chain; each handler decides whether to act.

🧠 Summary
Concept Description

Pattern Chain of Responsibility

Design Patterns Use Cases (Java And Spring) 163


Purpose Decouple sender and receivers

Key Benefit Flexibility in processing, avoids tight coupling

Real Uses Loggers, Authentication filters, Validation pipelines

Would you like to see this adapted for a Spring Boot-based middleware or
validator chain example?

You said:
use spring boot

ChatGPT said:
Let’s implement the Chain of Responsibility pattern in Spring Boot with a real-
world scenario.

✅ Use Case: Request Validation Chain


You want to process a user registration request through multiple steps:

1. Check if email is present

2. Check if password is strong enough

3. Check if user already exists

Each validation is implemented as a Spring bean, and chained dynamically using


the Chain of Responsibility pattern.

📁 Project Structure
src/
├── chain/
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
├── controller/
│ └── [Link]

Design Patterns Use Cases (Java And Spring) 164


├── model/
│ └── [Link]
├── [Link]

✅ 1. Define Base Handler ( RequestValidator )

package [Link];

import [Link];

public abstract class RequestValidator {


protected RequestValidator next;

public RequestValidator linkWith(RequestValidator nextValidator) {


[Link] = nextValidator;
return nextValidator;
}

public void validate(RegisterRequest request) {


handle(request);
if (next != null) {
[Link](request);
}
}

protected abstract void handle(RegisterRequest request);


}

✅ 2. Create Validators
[Link]

Design Patterns Use Cases (Java And Spring) 165


@Component
public class EmailValidator extends RequestValidator {
@Override
protected void handle(RegisterRequest request) {
if ([Link]() == null || ![Link]().contains("@")) {
throw new RuntimeException("Invalid email");
}
}
}

[Link]

@Component
public class PasswordValidator extends RequestValidator {
@Override
protected void handle(RegisterRequest request) {
if ([Link]() == null || [Link]().length() < 6) {
throw new RuntimeException("Password too short");
}
}
}

[Link]

@Component
public class UserExistValidator extends RequestValidator {
@Override
protected void handle(RegisterRequest request) {
if ("existing@[Link]".equals([Link]())) {
throw new RuntimeException("User already exists");
}
}
}


Design Patterns Use Cases (Java And Spring) 166
✅ 3. Create RegisterRequest DTO

package [Link];

public class RegisterRequest {


private String email;
private String password;

// Getters and setters


public String getEmail() { return email; }
public void setEmail(String email) { [Link] = email; }

public String getPassword() { return password; }


public void setPassword(String password) { [Link] = password; }
}

✅ 4. Create Controller to Use the Chain


@RestController
@RequestMapping("/api")
public class RegisterController {

private final EmailValidator emailValidator;


private final PasswordValidator passwordValidator;
private final UserExistValidator userExistValidator;

public RegisterController(EmailValidator emailValidator,


PasswordValidator passwordValidator,
UserExistValidator userExistValidator) {
[Link] = emailValidator;
[Link] = passwordValidator;
[Link] = userExistValidator;

// Link the chain

Design Patterns Use Cases (Java And Spring) 167


[Link](passwordValidator).linkWith(userExistValidator);
}

@PostMapping("/register")
public ResponseEntity<String> register(@RequestBody RegisterRequest re
quest) {
[Link](request);
return [Link]("Registration valid");
}
}

✅ 5. Main Application
@SpringBootApplication
public class SpringBootApp {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Sample Test with curl

curl -X POST [Link] \


-H "Content-Type: application/json" \
-d '{"email":"test@[Link]", "password":"123456"}'

✅ Returns: Registration valid

🔁 Chain Flow
If email is invalid → throws
Else → goes to password check

Design Patterns Use Cases (Java And Spring) 168


Else → goes to existing user check
Else → success!

🧠 Summary
Concept Applied With

Chain of Responsibility Spring Beans (Validators)

Chain Linked In Controller class

Real-World Use Case Request validation, filter chains, middleware

2. Command (Action Or Transaction)

The Command Design Pattern encapsulates a request as an object, thereby


allowing you to parameterize clients with queues, requests, and operations, and
support undoable operations.

✅ Real-World Use Case


Example: Remote Control System (like a smart home system)
You want to:

Turn a light on/off

Start/stop a fan

Schedule commands

Support undo

Each action (like turning on/off devices) can be encapsulated as a command


object.

✅ Participants in Command Pattern


Design Patterns Use Cases (Java And Spring) 169
Role Class

Command Command interface

ConcreteCommand LightOnCommand , etc.

Receiver Light , Fan , etc.

Invoker RemoteControl

Client Main class to bind them

✅ Java Implementation
1. Command Interface

public interface Command {


void execute();
void undo(); // optional: for undo functionality
}

2. Receiver Classes (Devices)

[Link]

public class Light {


public void turnOn() {
[Link]("Light is ON");
}

public void turnOff() {


[Link]("Light is OFF");
}
}

[Link]

Design Patterns Use Cases (Java And Spring) 170


public class Fan {
public void start() {
[Link]("Fan started");
}

public void stop() {


[Link]("Fan stopped");
}
}

3. Concrete Command Classes

[Link]

public class LightOnCommand implements Command {


private final Light light;

public LightOnCommand(Light light) {


[Link] = light;
}

public void execute() {


[Link]();
}

public void undo() {


[Link]();
}
}

[Link]

public class FanStartCommand implements Command {


private final Fan fan;

Design Patterns Use Cases (Java And Spring) 171


public FanStartCommand(Fan fan) {
[Link] = fan;
}

public void execute() {


[Link]();
}

public void undo() {


[Link]();
}
}

4. Invoker: RemoteControl

public class RemoteControl {


private Command command;

public void setCommand(Command command) {


[Link] = command;
}

public void pressButton() {


[Link]();
}

public void pressUndo() {


[Link]();
}
}

5. Client: [Link]

Design Patterns Use Cases (Java And Spring) 172


public class Main {
public static void main(String[] args) {
Light livingRoomLight = new Light();
Fan ceilingFan = new Fan();

Command lightOn = new LightOnCommand(livingRoomLight);


Command fanStart = new FanStartCommand(ceilingFan);

RemoteControl remote = new RemoteControl();

[Link](lightOn);
[Link](); // Light is ON
[Link](); // Light is OFF

[Link](fanStart);
[Link](); // Fan started
[Link](); // Fan stopped
}
}

✅ Output
Light is ON
Light is OFF
Fan started
Fan stopped

🧠 Benefits of the Command Pattern


Feature Benefit

Decouples sender from receiver Remote doesn’t need to know device internals

Supports undo Built-in undo method

Design Patterns Use Cases (Java And Spring) 173


Can queue/schedule commands Useful in task schedulers

Reusability Commands are reusable and composable

✅ Summary
Use Command pattern when you need to encapsulate operations or actions
as objects.

Works great for UI buttons, job queues, undo/redo features, or transactional


operations.

✅APIUse Case: Device Command Execution via REST


We'll simulate a system where the client can send commands like:

Turn light on/off

Start/stop fan

These commands are encapsulated as Command objects and executed through a


controller.

📦 Structure Overview
src/
├── command/
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
├── devices/

Design Patterns Use Cases (Java And Spring) 174


│ ├── [Link]
│ └── [Link]
├── controller/
│ └── [Link]
├── dto/
│ └── [Link]
└── [Link]

✅ 1. Command Interface

package [Link];

public interface Command {


String execute();
}

✅ 2. Device Classes (Receivers)


[Link]

package [Link];

import [Link];

@Component
public class Light {
public String turnOn() {
return "Light turned ON";
}

public String turnOff() {


return "Light turned OFF";

Design Patterns Use Cases (Java And Spring) 175


}
}

[Link]

package [Link];

import [Link];

@Component
public class Fan {
public String start() {
return "Fan started";
}

public String stop() {


return "Fan stopped";
}
}

✅ 3. Concrete Commands
[Link]

package [Link];

import [Link];

public class LightOnCommand implements Command {


private final Light light;

public LightOnCommand(Light light) {


[Link] = light;
}

Design Patterns Use Cases (Java And Spring) 176


@Override
public String execute() {
return [Link]();
}
}

[Link] (similarly create LightOffCommand ,


FanStartCommand )

package [Link];

import [Link];

public class FanStopCommand implements Command {


private final Fan fan;

public FanStopCommand(Fan fan) {


[Link] = fan;
}

@Override
public String execute() {
return [Link]();
}
}

✅ 4. [Link] – Invoker

package [Link];

import [Link];

@Component

Design Patterns Use Cases (Java And Spring) 177


public class CommandExecutor {
public String executeCommand(Command command) {
return [Link]();
}
}

✅ 5. [Link] – DTO

package [Link];

public class CommandRequest {


private String device;
private String action;

// getters and setters


public String getDevice() { return device; }
public void setDevice(String device) { [Link] = device; }

public String getAction() { return action; }


public void setAction(String action) { [Link] = action; }
}

✅ 6. [Link]

package [Link];

import [Link].*;
import [Link];
import [Link];
import [Link];
import [Link].*;

@RestController

Design Patterns Use Cases (Java And Spring) 178


@RequestMapping("/api/device")
public class DeviceController {

private final Light light;


private final Fan fan;
private final CommandExecutor executor;

public DeviceController(Light light, Fan fan, CommandExecutor executor) {


[Link] = light;
[Link] = fan;
[Link] = executor;
}

@PostMapping("/command")
public String executeCommand(@RequestBody CommandRequest request)
{
Command command;

switch ([Link]().toLowerCase()) {
case "light":
command = [Link]().equalsIgnoreCase("on")
? new LightOnCommand(light)
: new LightOffCommand(light);
break;

case "fan":
command = [Link]().equalsIgnoreCase("start")
? new FanStartCommand(fan)
: new FanStopCommand(fan);
break;

default:
return "Invalid device";
}

return [Link](command);

Design Patterns Use Cases (Java And Spring) 179


}
}

✅ 7. [Link]

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class SpringBootApp {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Test with CURL


Light ON

curl -X POST [Link] \


-H "Content-Type: application/json" \
-d '{"device": "light", "action": "on"}'

💡 Output:
Light turned ON

Fan STOP

Design Patterns Use Cases (Java And Spring) 180


curl -X POST [Link] \
-H "Content-Type: application/json" \
-d '{"device": "fan", "action": "stop"}'

💨 Output:
Fan stopped

🧠 Summary
Component Role
Command Encapsulates a request

Light , Fan Receivers


CommandExecutor Invoker
Controller Client
DTO Input abstraction

To integrate a Queue with the Command Design Pattern in Spring Boot, you can
enhance the CommandExecutor to enqueue and process commands asynchronously
or in batch — like a task scheduler, job queue, or command dispatcher.

✅ Updated Use Case


We'll modify our previous Spring Boot implementation to:

1. Queue commands.

2. Execute them in order (FIFO).

3. Optionally simulate delayed/background execution.

✅ Step-by-Step Enhancements
Design Patterns Use Cases (Java And Spring) 181
🔁 1. Modify CommandExecutor to Queue Commands

package [Link];

import [Link];
import [Link];
import [Link];

import [Link];
import [Link];

@Component
public class CommandExecutor {

private final Queue<Command> commandQueue = new LinkedList<>();

@PostConstruct
public void startExecutionLoop() {
// Start a background thread to execute commands
new Thread(this::processCommands).start();
}

public void enqueue(Command command) {


synchronized (commandQueue) {
[Link](command);
[Link](); // Wake up the processor thread
}
}

private void processCommands() {


while (true) {
Command command;
synchronized (commandQueue) {
while ([Link]()) {
try {
[Link](); // Wait for a command to arrive

Design Patterns Use Cases (Java And Spring) 182


} catch (InterruptedException e) {
[Link]().interrupt();
return;
}
}
command = [Link]();
}

if (command != null) {
String result = [Link]();
[Link]("[Executed] " + result);
}
}
}
}

⚙️Immediately
2. Modify Controller to Enqueue Instead of Execute

@PostMapping("/command")
public String enqueueCommand(@RequestBody CommandRequest request) {
Command command;

switch ([Link]().toLowerCase()) {
case "light":
command = [Link]().equalsIgnoreCase("on")
? new LightOnCommand(light)
: new LightOffCommand(light);
break;
case "fan":
command = [Link]().equalsIgnoreCase("start")
? new FanStartCommand(fan)
: new FanStopCommand(fan);
break;
default:

Design Patterns Use Cases (Java And Spring) 183


return "Invalid device or action";
}

[Link](command);
return "Command enqueued: " + [Link]() + " " + [Link]
ion();
}

🧪 Sample Output
When you call the endpoint:

curl -X POST [Link] \


-H "Content-Type: application/json" \
-d '{"device": "light", "action": "on"}'

Console logs:

Command enqueued: light on


[Executed] Light turned ON

✅ Optional: Use @Async for true background tasks


Enable @Async execution by adding:

[Link]

@SpringBootApplication
@EnableAsync
public class SpringBootApp { ... }

Then modify processCommands() to use @Async methods if you want parallel execution
(not FIFO).

🧠
Design Patterns Use Cases (Java And Spring) 184
🧠 Summary: Why Use Queue in Command Pattern?
Benefit Description

Decouples invocation & execution Useful in background job systems

FIFO processing Ensures order of command execution

Supports async workloads Schedule, batch, or throttle command dispatching

3. Interator

The Iterator pattern allows you to traverse a collection (like a list, set, or custom
data structure) one element at a time, without knowing its internal structure.

📦 Key Components
1. Iterator Interface – defines the methods for accessing elements ( hasNext() ,
next() ).

2. Concrete Iterator – implements the Iterator interface.

3. Aggregate Interface – defines a method to create an iterator.

4. Concrete Aggregate – returns an instance of the concrete iterator.

✅ Java Example
Step 1: Iterator Interface

public interface Iterator<T> {


boolean hasNext();
T next();
}

Step 2: Aggregate Interface

Design Patterns Use Cases (Java And Spring) 185


public interface Collection<T> {
Iterator<T> createIterator();
}

Step 3: Concrete Collection

public class NameRepository implements Collection<String> {


private String[] names = { "Sai", "Ashish", "Ravi", "Priya" };

@Override
public Iterator<String> createIterator() {
return new NameIterator();
}

private class NameIterator implements Iterator<String> {


int index = 0;

@Override
public boolean hasNext() {
return index < [Link];
}

@Override
public String next() {
return hasNext() ? names[index++] : null;
}
}
}

Step 4: Client Usage

public class Main {


public static void main(String[] args) {
NameRepository repo = new NameRepository();

Design Patterns Use Cases (Java And Spring) 186


Iterator<String> iterator = [Link]();

while ([Link]()) {
[Link]([Link]());
}
}
}

🧠 Use Cases
Custom collection frameworks – when creating your own data structures.

Traversal abstraction – when you want to hide the internal structure (tree,
graph, etc.).

Multiple traversals – forward, reverse, or filtered iteration.

Undo functionality – iterate over a history stack.

✅ Advantages
Promotes encapsulation by hiding collection internals.

Allows multiple traversals.

Clean separation between collection and traversal logic.

📍 Real-World Examples in Java


Java’s Iterator<E> interface in the [Link] package.

List<String> list = [Link]("A", "B", "C");


Iterator<String> itr = [Link]();
while ([Link]()) {
[Link]([Link]());
}

Design Patterns Use Cases (Java And Spring) 187


Implementing the Iterator Design Pattern in a Spring Boot application is similar to
the standard Java implementation—but it's typically used in contexts like:

Processing elements from a database or repository.

Iterating over services or tasks.

Streamlining batch operations.

Let’s walk through a realistic Spring Boot example where we simulate iterating
over a list of users from a database using a custom iterator.

🧩OneUse Case: User Iterator to Process Users One by


🔧 Step 1: Define the User Entity

@Entity
public class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;

private String name;


private String email;
// getters and setters
}

🗃️ Step 2: JPA Repository


@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

🔁 Step 3: Create the Iterator Interface


Design Patterns Use Cases (Java And Spring) 188
public interface Iterator<T> {
boolean hasNext();
T next();
}

📦 Step 4: User Collection and Iterator


public class UserCollection {
private List<User> users;

public UserCollection(List<User> users) {


[Link] = users;
}

public Iterator<User> getIterator() {


return new UserIterator();
}

private class UserIterator implements Iterator<User> {


private int index = 0;

@Override
public boolean hasNext() {
return index < [Link]();
}

@Override
public User next() {
return hasNext() ? [Link](index++) : null;
}
}
}

Design Patterns Use Cases (Java And Spring) 189


💡 Step 5: Service to Use the Iterator
@Service
public class UserService {

@Autowired
private UserRepository userRepository;

public void processUsers() {


List<User> allUsers = [Link]();
UserCollection userCollection = new UserCollection(allUsers);
Iterator<User> iterator = [Link]();

while ([Link]()) {
User user = [Link]();
[Link]("Processing user: " + [Link]());
}
}
}

🚀 Step 6: Trigger from Controller


@RestController
@RequestMapping("/users")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/process")
public String processUsers() {
[Link]();
return "User processing complete!";

Design Patterns Use Cases (Java And Spring) 190


}
}

✅ When to Use in Spring Boot


Streaming results (e.g., @Transactional with custom iterators).

Paginated processing using iterators.

Batch jobs or ETL pipelines.

Workflow or task orchestration over a list of steps/entities.

4. Intepreter

🧠 Interpreter Design Pattern in Java (Design Patterns)


The Interpreter pattern is a behavioral design pattern that is used to define a
grammar for a language and interpret sentences in that language using classes
representing grammar rules.

📚 Definition
The Interpreter Pattern defines a representation for a grammar
and provides an interpreter to deal with this grammar. It is used
when we want to evaluate language expressions.

⚙️ Use Case
Arithmetic expression evaluators ( 2 + 3 * 4 )

Rule engines

SQL parsing

Mini-language processing

Design Patterns Use Cases (Java And Spring) 191


Regex parsing

Search filters

🧩 Components of Interpreter Pattern


Component Description

Expression Abstract interface for all expressions

TerminalExpression Represents atomic expressions (e.g., numbers)

NonTerminalExpression Represents operators or rules (e.g., add, multiply)

Context Contains information global to the interpreter (can be optional)

✅ Java Example: Arithmetic Expression Evaluator


Step 1: Expression Interface

public interface Expression {


int interpret();
}

Step 2: TerminalExpression (Number)

public class Number implements Expression {


private int number;

public Number(int number) {


[Link] = number;
}

@Override
public int interpret() {
return number;

Design Patterns Use Cases (Java And Spring) 192


}
}

Step 3: NonTerminalExpressions (Add, Subtract)

public class Add implements Expression {


private Expression left, right;

public Add(Expression left, Expression right) {


[Link] = left;
[Link] = right;
}

@Override
public int interpret() {
return [Link]() + [Link]();
}
}

public class Subtract implements Expression {


private Expression left, right;

public Subtract(Expression left, Expression right) {


[Link] = left;
[Link] = right;
}

@Override
public int interpret() {
return [Link]() - [Link]();
}
}

Step 4: Client Usage

Design Patterns Use Cases (Java And Spring) 193


public class InterpreterPatternDemo {
public static void main(String[] args) {
// Represents: (5 + 3) - 2
Expression expr = new Subtract(
new Add(new Number(5), new Number(3)),
new Number(2)
);

[Link]("Result: " + [Link]()); // Output: 6


}
}

✅ Real-Life Use Cases


Domain Example

Spring Expression Language Used for evaluating expressions in config, security


(SpEL) rules, etc.

SQL Engines Parsing and interpreting queries

Rule Engines (e.g., Drools) Evaluating custom business logic

Custom Query Filters "price > 100 AND stock < 50"

❗️Pros and Cons


✅ Pros
Easy to add new expressions or operations

Good for small domain-specific languages (DSLs)

Clean, object-oriented grammar representation

❌ Cons
Becomes complex for large grammars

Lots of small classes (can lead to class explosion)

Design Patterns Use Cases (Java And Spring) 194


Not suitable for performance-critical code

5. Mediator

It allows you to encapsulate the interaction between objects


(colleagues) into a separate mediator object, improving code
maintainability and scalability.

The Mediator Design Pattern is a behavioral design pattern that centralizes


complex communications and control logic between related objects in a system,
promoting loose coupling by preventing objects from referring to each other
explicitly.

✅ Purpose of Mediator Pattern


It allows you to encapsulate the interaction between objects
(colleagues) into a separate mediator object, improving code
maintainability and scalability.

🧱 Key Components
Component Description
Mediator Interface that defines communication methods
ConcreteMediator Implements the mediator and coordinates interactions
Colleague Abstract class/component that interacts via the mediator
ConcreteColleague Implements behavior and delegates communication to mediator


Design Patterns Use Cases (Java And Spring) 195
✅ Java Implementation Example
🎯central
Use Case: Chatroom where users send messages through a
mediator

Step 1: Mediator Interface

public interface ChatMediator {


void sendMessage(String message, User sender);
void addUser(User user);
}

Step 2: Concrete Mediator

import [Link];
import [Link];

public class ChatRoom implements ChatMediator {


private List<User> users = new ArrayList<>();

@Override
public void sendMessage(String message, User sender) {
for (User user : users) {
if (user != sender) {
[Link](message);
}
}
}

@Override
public void addUser(User user) {
[Link](user);
}
}

Design Patterns Use Cases (Java And Spring) 196


Step 3: Abstract Colleague

public abstract class User {


protected ChatMediator mediator;
protected String name;

public User(ChatMediator mediator, String name) {


[Link] = mediator;
[Link] = name;
}

public abstract void send(String message);


public abstract void receive(String message);
}

Step 4: Concrete Colleague

public class ChatUser extends User {

public ChatUser(ChatMediator mediator, String name) {


super(mediator, name);
}

@Override
public void send(String message) {
[Link](name + " sends: " + message);
[Link](message, this);
}

@Override
public void receive(String message) {
[Link](name + " received: " + message);

Design Patterns Use Cases (Java And Spring) 197


}
}

Step 5: Client Demo

public class MediatorPatternDemo {


public static void main(String[] args) {
ChatMediator mediator = new ChatRoom();

User user1 = new ChatUser(mediator, "Alice");


User user2 = new ChatUser(mediator, "Bob");
User user3 = new ChatUser(mediator, "Charlie");

[Link](user1);
[Link](user2);
[Link](user3);

[Link]("Hello everyone!");
}
}

🧪 Output
Alice sends: Hello everyone!
Bob received: Hello everyone!
Charlie received: Hello everyone!

🧠 Real-World Use Cases


Scenario Example

UI Components A form where buttons, fields, and checkboxes update each


Communication other via a mediator

Design Patterns Use Cases (Java And Spring) 198


Chat Systems User-to-user or group chats

Planes communicate with the control tower, not directly with


Air Traffic Control System
each other

Workflow Engines Tasks communicate via a central controller

✅ Benefits
Reduces coupling between components

Centralizes logic for object communication

Improves code readability and maintainability

❌ Drawbacks
Mediator can become too complex and turn into a "God Object" if not handled
carefully

🧠 Use Case: Order Notification System


When a new order is placed:

Email service should notify the customer.

Inventory service should update stock.

Shipping service should prepare shipment.

🔁 Instead of each service calling others directly, we’ll use a mediator to


coordinate them — achieving loose coupling.

🧱 Project Structure
src/
└─ main/
└─ java/
└─ com/example/mediator/

Design Patterns Use Cases (Java And Spring) 199


├─ mediator/
│ ├─ [Link]
│ └─ [Link]
├─ services/
│ ├─ [Link]
│ ├─ [Link]
│ ├─ [Link]
├─ controller/
│ └─ [Link]
└─ [Link]

✅ 1. Define the Mediator Interface


package [Link];

import [Link];

public interface Mediator {


void notifyServices(Order order);
}

✅ 2. Define the Services (Colleagues)


package [Link];

import [Link];
import [Link];

@Service
public class EmailService {
public void sendConfirmation(Order order) {
[Link]("Email sent to customer for Order: " + [Link]());

Design Patterns Use Cases (Java And Spring) 200


}
}

package [Link];

import [Link];
import [Link];

@Service
public class InventoryService {
public void updateStock(Order order) {
[Link]("Inventory updated for Product: " + [Link]
());
}
}

package [Link];

import [Link];
import [Link];

@Service
public class ShippingService {
public void prepareShipment(Order order) {
[Link]("Shipment prepared for Order: " + [Link]());
}
}

✅ 3. Define the Order Model


package [Link];

public class Order {

Design Patterns Use Cases (Java And Spring) 201


private String id;
private String product;

// Constructor, getters
public Order(String id, String product) {
[Link] = id;
[Link] = product;
}

public String getId() { return id; }


public String getProduct() { return product; }
}

✅ 4. Implement the Concrete Mediator


package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

@Component
public class OrderMediator implements Mediator {

private final EmailService emailService;


private final InventoryService inventoryService;
private final ShippingService shippingService;

public OrderMediator(EmailService emailService, InventoryService inventor


yService, ShippingService shippingService) {
[Link] = emailService;
[Link] = inventoryService;

Design Patterns Use Cases (Java And Spring) 202


[Link] = shippingService;
}

@Override
public void notifyServices(Order order) {
[Link](order);
[Link](order);
[Link](order);
}
}

✅ 5. Controller to Trigger the Mediator


package [Link];

import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/orders")
public class OrderController {

private final Mediator orderMediator;

public OrderController(Mediator orderMediator) {


[Link] = orderMediator;
}

@PostMapping("/create")
public String createOrder(@RequestParam String id, @RequestParam String
product) {
Order order = new Order(id, product);
[Link](order);

Design Patterns Use Cases (Java And Spring) 203


return "Order processed successfully.";
}
}

✅ 6. Spring Boot Main Application


package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class MediatorApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

🧪 Sample Output on POST


id=123&product=Laptop
/orders/create?

Email sent to customer for Order: 123


Inventory updated for Product: Laptop
Shipment prepared for Order: 123

✅ Benefits in Spring Boot


Loose coupling between services

Easy to extend (add LoggingService etc.)

Easy testing: test mediator behavior separately

Follows Single Responsibility Principle

Design Patterns Use Cases (Java And Spring) 204


6. Memento

The Memento Design Pattern is a behavioral pattern used to capture and


externalize an object’s internal state so that it can be restored later without
violating encapsulation.

✅ Intent
“Without exposing the object’s internal structure, you can save
and restore its state.

🧱 Key Components
Role Description
Originator The object whose state needs to be saved and restored
Memento Stores the internal state of the Originator ; it’s immutable to others

Maintains a list of mementos and controls save/restore without accessing


Caretaker
their data

✅ Use Case Example in Java


🎯 Scenario: Text Editor with Undo Functionality
🔹 1. Memento Class (Immutable)
public class TextEditorMemento {
private final String content;

public TextEditorMemento(String content) {


[Link] = content;

Design Patterns Use Cases (Java And Spring) 205


}

public String getContent() {


return content;
}
}

🔹 2. Originator (Text Editor)


public class TextEditor {
private String content = "";

public void type(String words) {


content += words;
}

public String getContent() {


return content;
}

public TextEditorMemento save() {


return new TextEditorMemento(content);
}

public void restore(TextEditorMemento memento) {


[Link] = [Link]();
}
}

🔹 3. Caretaker (History)
import [Link];

public class EditorHistory {

Design Patterns Use Cases (Java And Spring) 206


private Stack<TextEditorMemento> history = new Stack<>();

public void save(TextEditor editor) {


[Link]([Link]());
}

public void undo(TextEditor editor) {


if (![Link]()) {
[Link]([Link]());
}
}
}

🔹 4. Client (Demo)
public class MementoPatternDemo {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
EditorHistory history = new EditorHistory();

[Link]("Hello ");
[Link](editor); // Save 1

[Link]("World!");
[Link](editor); // Save 2

[Link](" This will be undone.");

[Link]("Current Content: " + [Link]());

[Link](editor);
[Link]("After Undo 1: " + [Link]());

[Link](editor);
[Link]("After Undo 2: " + [Link]());

Design Patterns Use Cases (Java And Spring) 207


}
}

✅ Output:
Current Content: Hello World! This will be undone.
After Undo 1: Hello World!
After Undo 2: Hello

💡 Real-World Use Cases


Use Case Example

Undo/Redo in editors Text editors (Notepad, Word, etc.)

Game Save/Load Saving a game state to resume later

Workflow snapshots Save intermediate workflow state for rollback

Versioning Object version history (drafts, edits)

Database transactions Rollback logic where a memento stores object state before
(manual) a transaction

✅ Benefits
Preserves encapsulation

Easy to implement undo/rollback features

Cleaner separation between state management and business logic

❌ Drawbacks
Can consume a lot of memory if many states are saved

Caretaker must manage lifecycle carefully


Design Patterns Use Cases (Java And Spring) 208
✅ Project Structure
memento-spring-boot/
├── controller/
│ └── [Link]
├── model/
│ └── [Link]
├── service/
│ ├── [Link]
│ └── [Link]
└── [Link]

🔹 1. [Link] (Model)

package [Link];

public class Memento {


private final String content;

public Memento(String content) {


[Link] = content;
}

public String getContent() {


return content;
}
}

🔹 2. [Link] (Originator)

Design Patterns Use Cases (Java And Spring) 209


package [Link];

import [Link];
import [Link];

@Service
public class EditorService {
private String content = "";

public void type(String newContent) {


content += newContent;
}

public Memento save() {


return new Memento(content);
}

public void restore(Memento memento) {


[Link] = [Link]();
}

public String getContent() {


return content;
}
}

🔹 3. [Link] (Caretaker)

package [Link];

import [Link];
import [Link];

Design Patterns Use Cases (Java And Spring) 210


import [Link];

@Service
public class HistoryService {
private final Stack<Memento> history = new Stack<>();

public void save(Memento memento) {


[Link](memento);
}

public Memento undo() {


return [Link]() ? new Memento("") : [Link]();
}

public boolean hasHistory() {


return ![Link]();
}
}

🔹 4. [Link]

import [Link];

import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/editor")
public class EditorController {

private final EditorService editorService;


private final HistoryService historyService;

Design Patterns Use Cases (Java And Spring) 211


public EditorController(EditorService editorService, HistoryService historyS
ervice) {
[Link] = editorService;
[Link] = historyService;
}

@PostMapping("/type")
public String type(@RequestParam String text) {
[Link](text);
return "Typed: " + text;
}

@PostMapping("/save")
public String save() {
[Link]([Link]());
return "State saved.";
}

@PostMapping("/undo")
public String undo() {
if ([Link]()) {
[Link]([Link]());
return "Undo successful.";
}
return "No history to undo.";
}

@GetMapping("/content")
public String content() {
return [Link]();
}
}

🔹
Design Patterns Use Cases (Java And Spring) 212
🔹 5. [Link] (Main App)

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class MementoApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Sample API Usage


1. POST /editor/type?text=Hello

2. POST /editor/save

3. POST /editor/type?text=World!

4. GET /editor/content → Hello World!

5. POST /editor/undo

6. GET /editor/content → Hello

📦 Dependencies (in [Link] )

<dependencies>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>


Design Patterns Use Cases (Java And Spring) 213
✅ Summary
Component Pattern Role
EditorService Originator
Memento Memento
HistoryService Caretaker
EditorController Client / API

7. Null State

The Null Object Design Pattern provides an object as a surrogate for the absence
of a real object. Instead of returning null , return a special object that implements
the expected interface but does nothing (a “do-nothing” implementation). This
helps eliminate null checks and NullPointerExceptions .

✅ When to Use
To avoid null checks and reduce conditional logic.

To provide a default behavior when no object is present.

To simplify code, especially in object-oriented designs.

✅ Structure
Abstract Class / Interface: Declares the common operations.

Real Object: Implements actual behavior.

Null Object: Implements the same interface with empty or default behavior.

Client: Uses interface without worrying about null .

✅ Example: Customer Lookup


Design Patterns Use Cases (Java And Spring) 214
Imagine a system where you retrieve a Customer by name. If not found, instead of
returning null , we return a NullCustomer .

🔹 1. Define the Interface


public interface Customer {
String getName();
boolean isNull();
}

🔹 2. Create Real Customer Class


public class RealCustomer implements Customer {
private final String name;

public RealCustomer(String name) {


[Link] = name;
}

@Override
public String getName() {
return name;
}

@Override
public boolean isNull() {
return false;
}
}

🔹 3. Create Null Customer Class


public class NullCustomer implements Customer {

Design Patterns Use Cases (Java And Spring) 215


@Override
public String getName() {
return "Not Available";
}

@Override
public boolean isNull() {
return true;
}
}

🔹 4. CustomerFactory
public class CustomerFactory {
private static final String[] names = {"Alice", "Bob", "Charlie"};

public static Customer getCustomer(String name) {


for (String n : names) {
if ([Link](name)) {
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}

🔹 5. Client Code
public class Main {
public static void main(String[] args) {
Customer c1 = [Link]("Bob");
Customer c2 = [Link]("Unknown");

[Link]([Link]()); // Output: Bob

Design Patterns Use Cases (Java And Spring) 216


[Link]([Link]()); // Output: Not Available
}
}

✅ Advantages of Null Object Pattern


Benefit Description

Avoids null checks No need to check if (x != null)

Prevents NullPointerException Null object handles default behavior

Clean and maintainable code Promotes polymorphism over conditionals

Improves testability Behavior can be easily mocked or replaced

✅ Real-world Use Cases


Context Use Case

Repositories findById() returns NullObject if not found

Logging NoOpLogger avoids logging if disabled

Strategy Pattern Fallback behavior when no strategy matches

User Sessions Return a GuestUser instead of null session

Spring Boot Use Optional beans or empty object patterns

8. Observer

The Observer Design Pattern is a behavioral design pattern that defines a one-
to-many dependency between objects so that when one object (the Subject)
changes state, all its dependents (Observers) are notified and updated
automatically.


Design Patterns Use Cases (Java And Spring) 217
✅ Key Components
Role Description

Subject Maintains a list of observers and notifies them

Observer Defines an updating interface

ConcreteSubject Stores state and notifies observers

ConcreteObserver Implements the observer interface

✅ Real-world Analogy
A YouTube Channel (Subject) notifies all its Subscribers (Observers) when a new
video is uploaded.

✅ Example in Java: Notification System


Let’s implement a simple system where users subscribe to a news agency, and
are notified when news is published.

🔹 1. [Link] (Interface)

public interface Observer {


void update(String message);
}

🔹 2. [Link] (Interface)

public interface Subject {


void subscribe(Observer observer);
void unsubscribe(Observer observer);
void notifyObservers(String message);
}

🔹 3. [Link] (ConcreteSubject)

Design Patterns Use Cases (Java And Spring) 218


import [Link];
import [Link];

public class NewsAgency implements Subject {


private final List<Observer> observers = new ArrayList<>();

@Override
public void subscribe(Observer observer) {
[Link](observer);
}

@Override
public void unsubscribe(Observer observer) {
[Link](observer);
}

@Override
public void notifyObservers(String message) {
for (Observer observer : observers) {
[Link](message);
}
}

public void publishNews(String news) {


[Link]("Publishing news: " + news);
notifyObservers(news);
}
}

🔹 4. [Link] (ConcreteObserver)

public class Subscriber implements Observer {


private final String name;

Design Patterns Use Cases (Java And Spring) 219


public Subscriber(String name) {
[Link] = name;
}

@Override
public void update(String message) {
[Link](name + " received update: " + message);
}
}

🔹 5. Main Class
public class Main {
public static void main(String[] args) {
NewsAgency agency = new NewsAgency();

Observer alice = new Subscriber("Alice");


Observer bob = new Subscriber("Bob");

[Link](alice);
[Link](bob);

[Link]("Breaking News: Observer pattern rocks!");


[Link](alice);
[Link]("Update: Alice unsubscribed.");
}
}

✅ Output
Breaking News: Observer pattern rocks!
Alice received update: Breaking News: Observer pattern rocks!
Bob received update: Breaking News: Observer pattern rocks!

Design Patterns Use Cases (Java And Spring) 220


Publishing news: Update: Alice unsubscribed.
Bob received update: Update: Alice unsubscribed.

✅ Use Cases
Use Case Description

Event handling systems UI components listening to user input

Messaging & Notification Email, SMS, or push notifications

Stock market applications Observers watch for stock price changes

Chat applications Listeners receive messages in real time

Spring Framework ApplicationEventPublisher and listeners

Here’s how you can implement the Observer Design Pattern using Spring Boot,
simulating a news publishing system where:

Admin can publish news.

Users (observers) are notified.

✅ Overview
We'll build:

Observer interface ( Subscriber )

Subject class ( NewsAgency )

A simple REST API to:

Register subscribers

Publish news

Notify all subscribers

✅ Step-by-Step Spring Boot Setup


🔹 1. Project Structure
Design Patterns Use Cases (Java And Spring) 221
src/main/java/
└── com/example/observer
├── [Link]
├── [Link]
├── [Link]
├── [Link]
└── [Link]

🔹 2. [Link]

package [Link];

public interface Observer {


void update(String message);
String getName();
}

🔹 3. [Link]

package [Link];

public class Subscriber implements Observer {


private final String name;

public Subscriber(String name) {


[Link] = name;
}

@Override
public void update(String message) {
[Link]("[" + name + "] received: " + message);
}

Design Patterns Use Cases (Java And Spring) 222


@Override
public String getName() {
return name;
}
}

🔹 4. [Link]

package [Link];

import [Link];

import [Link];
import [Link];

@Component
public class NewsAgency {

private final List<Observer> subscribers = new ArrayList<>();

public void subscribe(Observer observer) {


[Link](observer);
}

public void unsubscribe(String name) {


[Link](subscriber -> [Link]().equalsIgnoreC
ase(name));
}

public List<String> getSubscribers() {


return [Link]().map(Observer::getName).toList();
}

public void publishNews(String news) {

Design Patterns Use Cases (Java And Spring) 223


for (Observer subscriber : subscribers) {
[Link](news);
}
}
}

🔹 5. [Link]

import [Link];

import [Link].*;

import [Link];

@RestController
@RequestMapping("/news")
public class NewsController {

private final NewsAgency newsAgency;

public NewsController(NewsAgency newsAgency) {


[Link] = newsAgency;
}

@PostMapping("/subscribe")
public String subscribe(@RequestParam String name) {
[Link](new Subscriber(name));
return "Subscribed: " + name;
}

@DeleteMapping("/unsubscribe")
public String unsubscribe(@RequestParam String name) {
[Link](name);
return "Unsubscribed: " + name;
}

Design Patterns Use Cases (Java And Spring) 224


@PostMapping("/publish")
public String publish(@RequestParam String message) {
[Link](message);
return "News published: " + message;
}

@GetMapping("/subscribers")
public List<String> getSubscribers() {
return [Link]();
}
}

🔹 6. [Link]

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class ObserverApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Sample API Usage (Postman or cURL)


# Subscribe
curl -X POST "[Link]
curl -X POST "[Link]

Design Patterns Use Cases (Java And Spring) 225


# Publish news
curl -X POST "[Link]
s%21"

# Unsubscribe
curl -X DELETE "[Link]

# Get all subscribers


curl "[Link]

✅ Console Output (on publish)


[Alice] received: Breaking News!
[Bob] received: Breaking News!

9. State

The State Design Pattern is a behavioral pattern that allows an object to change
its behavior when its internal state changes. It appears as if the object changed
its class.

✅ Intent
Encapsulate state-based behavior and delegate to the current state object.

✅ Real-world Analogy
Consider a Vending Machine:

When money is inserted, it moves to the Ready state.

If selection is made, it moves to Dispensing state.

Design Patterns Use Cases (Java And Spring) 226


If out of stock, it enters OutOfStock state.

✅ Key Participants
Role Description

Context Maintains an instance of a ConcreteState subclass

State (interface) Defines the interface for behavior associated with a state of Context

ConcreteStates Each subclass implements behavior specific to the state

✅ Java Example: TrafficLight System


We'll implement a traffic light that changes from Red → Green → Yellow → Red...

🔹 1. [Link] (State Interface)

public interface State {


void handleRequest(TrafficLight context);
String getColor();
}

🔹 2. [Link]

public class RedState implements State {


@Override
public void handleRequest(TrafficLight context) {
[Link](new GreenState());
}

@Override
public String getColor() {
return "Red";
}
}

Design Patterns Use Cases (Java And Spring) 227


🔹 3. [Link]

public class GreenState implements State {


@Override
public void handleRequest(TrafficLight context) {
[Link](new YellowState());
}

@Override
public String getColor() {
return "Green";
}
}

🔹 4. [Link]

public class YellowState implements State {


@Override
public void handleRequest(TrafficLight context) {
[Link](new RedState());
}

@Override
public String getColor() {
return "Yellow";
}
}

🔹 5. [Link] (Context)

public class TrafficLight {


private State currentState;

Design Patterns Use Cases (Java And Spring) 228


public TrafficLight() {
currentState = new RedState(); // initial state
}

public void setState(State state) {


[Link] = state;
}

public void next() {


[Link](this);
}

public String getCurrentColor() {


return [Link]();
}
}

🔹 6. Main Class
public class Main {
public static void main(String[] args) {
TrafficLight light = new TrafficLight();

for (int i = 0; i < 6; i++) {


[Link]("Light: " + [Link]());
[Link]();
}
}
}

✅ Output
makefile
CopyEdit

Design Patterns Use Cases (Java And Spring) 229


Light: Red
Light: Green
Light: Yellow
Light: Red
Light: Green
Light: Yellow

✅ Use Cases of State Design Pattern


Use Case Description

Workflow/Process engines e.g., Order states: Placed → Shipped → Delivered

Game development Player states: Idle, Running, Jumping, Attacking

UI components Button states: Enabled, Disabled, Hovered, Clicked

TCP connection states OPEN, LISTEN, CLOSED, SYN_SENT, etc.

ATM machine NoCard, HasCard, Authorized, OutOfService

✅ 1. [Link] (interface)

package [Link];

import [Link];

public interface State {


void handle(TrafficLightContext context);
String getColor();
}

✅ 2. Concrete States
🔸 [Link]

Design Patterns Use Cases (Java And Spring) 230


package [Link];

import [Link];
import [Link];

@Component
public class RedState implements State {
@Override
public void handle(TrafficLightContext context) {
[Link]([Link]());
}

@Override
public String getColor() {
return "Red";
}
}

🔸 [Link]

package [Link];

import [Link];
import [Link];

@Component
public class GreenState implements State {
@Override
public void handle(TrafficLightContext context) {
[Link]([Link]());
}

@Override

Design Patterns Use Cases (Java And Spring) 231


public String getColor() {
return "Green";
}
}

🔸 [Link]

package [Link];

import [Link];
import [Link];

@Component
public class YellowState implements State {
@Override
public void handle(TrafficLightContext context) {
[Link]([Link]());
}

@Override
public String getColor() {
return "Yellow";
}
}

✅ 3. [Link]

package [Link];

import [Link].*;
import [Link];
import [Link];

@Component

Design Patterns Use Cases (Java And Spring) 232


public class TrafficLightContext {

private final RedState redState;


private final GreenState greenState;
private final YellowState yellowState;

private State currentState;

public TrafficLightContext(RedState red, GreenState green, YellowState yell


ow) {
[Link] = red;
[Link] = green;
[Link] = yellow;
}

@PostConstruct
public void init() {
currentState = redState; // initial state
}

public void next() {


[Link](this);
}

public String getCurrentStateColor() {


return [Link]();
}

public void setState(State state) {


[Link] = state;
}

public RedState getRedState() { return redState; }


public GreenState getGreenState() { return greenState; }

Design Patterns Use Cases (Java And Spring) 233


public YellowState getYellowState() { return yellowState; }
}

✅ 4. [Link]

package [Link];

import [Link];
import [Link].*;

@RestController
@RequestMapping("/traffic-light")
public class TrafficLightController {

private final TrafficLightContext context;

public TrafficLightController(TrafficLightContext context) {


[Link] = context;
}

@GetMapping("/state")
public String getCurrentState() {
return "Current State: " + [Link]();
}

@PostMapping("/next")
public String goToNextState() {
[Link]();
return "Transitioned to: " + [Link]();
}
}

✅ 5. [Link]

Design Patterns Use Cases (Java And Spring) 234


package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class StatePatternApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Test Using cURL or Postman


# Get current state
curl [Link]

# Transition to next state


curl -X POST [Link]

✅ Sample Output
GET /state → Current State: Red
POST /next → Transitioned to: Green
POST /next → Transitioned to: Yellow
POST /next → Transitioned to: Red

10. Strategy

The Strategy Design Pattern is a behavioral pattern used to define a family of


algorithms, encapsulate each one, and make them interchangeable at runtime. It
enables selecting an algorithm's behavior at runtime.

Design Patterns Use Cases (Java And Spring) 235


✅ Real-World Analogy
Think of a navigation app:

You can choose between different route strategies like:

Fastest route

Shortest distance

Avoid tolls

Each strategy is encapsulated and can be changed without modifying the


navigation logic.

✅ Participants
Component Role
Strategy Interface for all supported algorithms
ConcreteStrategy Implementation of the algorithm
Context Uses a Strategy object to call the algorithm

✅ Java Example: Payment Strategy


We’ll implement a payment system where users can choose between:

Credit Card

PayPal

UPI

🔹 1. [Link] (Strategy Interface)

interface PaymentStrategy {
void pay(double amount);
}

Design Patterns Use Cases (Java And Spring) 236


🔹 2. Concrete Strategies
[Link]

public class CreditCardPayment implements PaymentStrategy {


private String cardNumber;

public CreditCardPayment(String cardNumber) {


[Link] = cardNumber;
}

@Override
public void pay(double amount) {
[Link]("Paid ₹" + amount + " using Credit Card: " + cardNum
ber);
}
}

[Link]

public class PayPalPayment implements PaymentStrategy {


private String email;

public PayPalPayment(String email) {


[Link] = email;
}

@Override
public void pay(double amount) {
[Link]("Paid ₹" + amount + " using PayPal: " + email);
}
}

[Link]

Design Patterns Use Cases (Java And Spring) 237


public class UPIPayment implements PaymentStrategy {
private String upiId;

public UPIPayment(String upiId) {


[Link] = upiId;
}

@Override
public void pay(double amount) {
[Link]("Paid ₹" + amount + " using UPI: " + upiId);
}
}

🔹 3. [Link] (Context)

public class PaymentContext {


private PaymentStrategy paymentStrategy;

public void setPaymentStrategy(PaymentStrategy strategy) {


[Link] = strategy;
}

public void processPayment(double amount) {


if (paymentStrategy == null) {
throw new IllegalStateException("Payment strategy not set");
}
[Link](amount);
}
}

🔹 4. Main Method

Design Patterns Use Cases (Java And Spring) 238


public class Main {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();

[Link](new CreditCardPayment("1234-5678-9012-
3456"));
[Link](500.0);

[Link](new PayPalPayment("user@[Link]
m"));
[Link](250.0);

[Link](new UPIPayment("user@upi"));
[Link](100.0);
}
}

✅ Output
Credit Card: 1234-5678-9012-3456
Paid ₹250.0 using PayPal: user@[Link]
Paid ₹100.0 using UPI: user@upi

✅ Use Cases of Strategy Pattern


Use Case Example

Payment gateways Switch between different payment processors dynamically

Compression algorithms Support ZIP, RAR, TAR, etc.

Choose QuickSort, MergeSort, BubbleSort based on dataset


Sorting strategies
size

Validation strategies Apply different validation based on user type or context

Route selection GPS apps: fastest vs shortest vs scenic

Design Patterns Use Cases (Java And Spring) 239


Tax calculations Different tax rules for regions or countries

Authentication
JWT, OAuth2, Basic Auth, API Key strategies
mechanisms

✅ Goal
Create a Spring Boot app where:

Multiple PaymentStrategy implementations exist.

A user can choose a strategy via API (e.g., PayPal, Credit Card, UPI).

Strategy is resolved at runtime.

✅ 1. Project Structure
spring-strategy-demo/
├── controller/
│ └── [Link]
├── strategy/
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
└── [Link]

✅ 2. Define the Strategy Interface


package [Link];

public interface PaymentStrategy {


void pay(double amount);
}

Design Patterns Use Cases (Java And Spring) 240


✅ 3. Concrete Strategies
// strategy/[Link]
package [Link];

import [Link];

@Component("paypal")
public class PayPalPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
[Link]("Paid ₹" + amount + " using PayPal");
}
}

// strategy/[Link]
package [Link];

import [Link];

@Component("creditcard")
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
[Link]("Paid ₹" + amount + " using Credit Card");
}
}

// strategy/[Link]
package [Link];

import [Link];

@Component("upi")

Design Patterns Use Cases (Java And Spring) 241


public class UPIPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
[Link]("Paid ₹" + amount + " using UPI");
}
}

✅ 4. Strategy Factory (Auto-wired by Bean name)


// [Link]
package [Link];

import [Link];
import [Link];

import [Link];

@Component
public class PaymentStrategyFactory {

private final Map<String, PaymentStrategy> strategyMap;

@Autowired
public PaymentStrategyFactory(Map<String, PaymentStrategy> strategyMa
p) {
[Link] = strategyMap;
}

public PaymentStrategy getStrategy(String type) {


PaymentStrategy strategy = [Link]([Link]());
if (strategy == null) {
throw new IllegalArgumentException("Invalid payment type: " + type);
}
return strategy;

Design Patterns Use Cases (Java And Spring) 242


}
}

✅ 5. REST Controller
// controller/[Link]
package [Link];

import [Link];
import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/api/payment")
public class PaymentController {

@Autowired
private PaymentStrategyFactory strategyFactory;

@PostMapping
public String pay(@RequestParam double amount, @RequestParam String
method) {
PaymentStrategy strategy = [Link](method);
[Link](amount);
return "Payment of ₹" + amount + " via " + method + " completed.";
}
}

✅ 6. Main Class
package [Link];

import [Link];

Design Patterns Use Cases (Java And Spring) 243


import [Link];

@SpringBootApplication
public class SpringStrategyDemoApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

✅ Run & Test


Start the app and use Postman or cURL:

curl -X POST "[Link]


pal"

Output (console):

Paid ₹1500.0 using PayPal

✅ Benefits of Using Strategy with Spring


No if-else or switch-case .

Easy to add new strategies (just @Component ).

Runtime selection based on REST param.

Clean, scalable, and testable.

11. Template

Design Patterns Use Cases (Java And Spring) 244


Template Method Design Pattern
✅ Intent
Define the skeleton of an algorithm in a method, deferring
some steps to subclasses. Template Method lets subclasses
override certain steps of the algorithm without changing its
structure.

✅ What it means
You have a general algorithm with fixed steps, but some steps can vary depending
on the subclass. You put the fixed sequence in a method (the template method)
and let subclasses provide the implementation for the variable steps.

✅ Real-world analogy
Think of making a tea or coffee. The sequence is:

1. Boil water

2. Brew beverage (tea leaves or coffee powder)

3. Pour into cup

4. Add condiments (milk, sugar)

Steps 1, 3 are fixed, but steps 2 and 4 vary depending on the drink.

✅ Structure
Component Description

Defines the template method (algorithm skeleton). Contains some


AbstractClass
abstract operations to be implemented by subclasses.

ConcreteClass Implements the variable steps of the algorithm.

Java Example

Design Patterns Use Cases (Java And Spring) 245


1. Abstract Class (Template)

public abstract class Beverage {

// Template method defining the sequence


public final void prepare() {
boilWater();
brew();
pourInCup();
addCondiments();
}

private void boilWater() {


[Link]("Boiling water");
}

// Abstract methods to be implemented by subclasses


protected abstract void brew();

private void pourInCup() {


[Link]("Pouring into cup");
}

protected abstract void addCondiments();


}

2. Concrete Classes

public class Tea extends Beverage {

@Override
protected void brew() {
[Link]("Steeping the tea leaves");
}

Design Patterns Use Cases (Java And Spring) 246


@Override
protected void addCondiments() {
[Link]("Adding lemon");
}
}

public class Coffee extends Beverage {

@Override
protected void brew() {
[Link]("Dripping coffee through filter");
}

@Override
protected void addCondiments() {
[Link]("Adding sugar and milk");
}
}

3. Client code

public class Main {


public static void main(String[] args) {
Beverage tea = new Tea();
[Link]();

[Link]();

Beverage coffee = new Coffee();


[Link]();
}
}

Design Patterns Use Cases (Java And Spring) 247


Output

Boiling water
Steeping the tea leaves
Pouring into cup
Adding lemon

Boiling water
Dripping coffee through filter
Pouring into cup
Adding sugar and milk

✅ Use Cases for Template Method Pattern


Use Case Explanation

Frameworks where basic workflow E.g., JUnit testing framework uses template methods
is fixed for test lifecycle ( setUp , tearDown ).

Algorithms with invariant structure Sorting algorithms that share common parts but vary
but variable steps the pivot choice.

Code reuse with common Base classes define the skeleton, subclasses override
algorithm parts details.

Workflow engines and batch jobs Fixed steps with flexible sub-tasks inside a process.

Rendering lifecycle with customizable rendering


UI frameworks
steps.

Generic parse method with steps overridden by


Parsing and compiling
different language parsers.

Scenario
We have a service that sends notifications. The basic flow (algorithm) to send a
notification is:

1. Validate the notification data

2. Prepare the message

Design Patterns Use Cases (Java And Spring) 248


3. Send the notification

4. Log the result

Steps 1 and 4 are fixed for all notifications. Steps 2 and 3 vary for different
notification types like Email and SMS.

Step-by-step Spring Boot implementation

1. Abstract Template Service

package [Link];

public abstract class NotificationService {

// Template method
public final void sendNotification(String to, String message) {
validate(to, message);
String preparedMessage = prepareMessage(message);
send(preparedMessage, to);
log();
}

private void validate(String to, String message) {


if (to == null || [Link]()) {
throw new IllegalArgumentException("Recipient cannot be empty");
}
if (message == null || [Link]()) {
throw new IllegalArgumentException("Message cannot be empty");
}
}

// Steps to be implemented by subclasses


protected abstract String prepareMessage(String message);

protected abstract void send(String message, String to);

Design Patterns Use Cases (Java And Spring) 249


// Fixed logging step
private void log() {
[Link]("Notification sent successfully");
}
}

2. Concrete Notification Services

package [Link];

import [Link];

@Service("emailNotificationService")
public class EmailNotificationService extends NotificationService {

@Override
protected String prepareMessage(String message) {
return "Email Content: " + message;
}

@Override
protected void send(String message, String to) {
[Link]("Sending Email to " + to + " with message: " + messag
e);
}
}

package [Link];

import [Link];

@Service("smsNotificationService")
public class SmsNotificationService extends NotificationService {

Design Patterns Use Cases (Java And Spring) 250


@Override
protected String prepareMessage(String message) {
return "SMS Content: " + message;
}

@Override
protected void send(String message, String to) {
[Link]("Sending SMS to " + to + " with message: " + messag
e);
}
}

3. Controller to choose strategy dynamically

package [Link];

import [Link];
import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/api/notify")
public class NotificationController {

@Autowired
@Qualifier("emailNotificationService")
private NotificationService emailNotificationService;

@Autowired
@Qualifier("smsNotificationService")
private NotificationService smsNotificationService;

@PostMapping

Design Patterns Use Cases (Java And Spring) 251


public String sendNotification(@RequestParam String type,
@RequestParam String to,
@RequestParam String message) {

NotificationService service;

switch ([Link]()) {
case "email":
service = emailNotificationService;
break;
case "sms":
service = smsNotificationService;
break;
default:
throw new IllegalArgumentException("Invalid notification type");
}

[Link](to, message);
return "Notification sent via " + type;
}
}

4. Main Spring Boot application

package [Link];

import [Link];
import [Link];

@SpringBootApplication
public class NotificationTemplateApp {
public static void main(String[] args) {
[Link]([Link], args);

Design Patterns Use Cases (Java And Spring) 252


}
}

How to test
Start the app and send POST requests:

curl -X POST "[Link]


com&message=HelloEmail"

Output console:

Sending Email to user@[Link] with message: Email Content: HelloEmail


Notification sent successfully

curl -X POST "[Link]


essage=HelloSMS"

Output console:

Sending SMS to 9999999999 with message: SMS Content: HelloSMS


Notification sent successfully

✅ Summary
Template Method defines fixed steps + customizable hooks.

Spring @Service components implement different variants.

Controller dynamically picks the correct implementation based on input.

12. Visitor

Design Patterns Use Cases (Java And Spring) 253


Visitor Design Pattern
✅ Intent
Separate an algorithm from the objects on which it operates.

Visitor lets you add further operations to objects without


modifying them.

✅ Why use Visitor?


When you want to perform operations across a complex object structure (like
different types in a class hierarchy).

Avoid cluttering classes with unrelated operations.

Add new operations easily without changing existing classes.

✅ Structure
Component Description

Visitor Declares visit methods for each concrete element type.

ConcreteVisitor Implements operations to be performed on elements.

Element Defines an accept method that takes a visitor.

ConcreteElement Implements accept to call visitor’s visit method.

ObjectStructure Collection or complex object with elements to accept visitors.

Java Example: Shopping Cart with different Item types

1. Element interface

public interface ItemElement {


void accept(ShoppingCartVisitor visitor);
}

Design Patterns Use Cases (Java And Spring) 254


2. Concrete Elements (different items)

public class Book implements ItemElement {


private int price;
private String isbnNumber;

public Book(int price, String isbn) {


[Link] = price;
[Link] = isbn;
}

public int getPrice() { return price; }


public String getIsbnNumber() { return isbnNumber; }

@Override
public void accept(ShoppingCartVisitor visitor) {
[Link](this);
}
}

public class Fruit implements ItemElement {


private int pricePerKg;
private int weight;
private String name;

public Fruit(int pricePerKg, int weight, String name) {


[Link] = pricePerKg;
[Link] = weight;
[Link] = name;
}

public int getPricePerKg() { return pricePerKg; }


public int getWeight() { return weight; }
public String getName() { return name; }

Design Patterns Use Cases (Java And Spring) 255


@Override
public void accept(ShoppingCartVisitor visitor) {
[Link](this);
}
}

3. Visitor Interface

public interface ShoppingCartVisitor {


void visit(Book book);
void visit(Fruit fruit);
}

4. Concrete Visitor implementing operation

public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {

@Override
public void visit(Book book) {
int cost = [Link]();
[Link]("Book ISBN::" + [Link]() + " cost = " +
cost);
}

@Override
public void visit(Fruit fruit) {
int cost = [Link]() * [Link]();
[Link]([Link]() + " cost = " + cost);
}
}

5. Client code

Design Patterns Use Cases (Java And Spring) 256


public class ShoppingCartClient {
public static void main(String[] args) {
ItemElement[] items = new ItemElement[] {
new Book(20, "1234"),
new Book(100, "5678"),
new Fruit(10, 2, "Banana"),
new Fruit(5, 5, "Apple")
};

int total = 0;
ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();

for (ItemElement item : items) {


[Link](visitor); // double dispatch
}
}
}

Output

Book ISBN::1234 cost = 20


Book ISBN::5678 cost = 100
Banana cost = 20
Apple cost = 25

Summary
Visitor decouples operations from object structure.

Uses double dispatch:

1. Object calls accept(visitor) .

2. Visitor calls visit(concreteElement) .

Easy to add new operations without modifying elements.

Design Patterns Use Cases (Java And Spring) 257


Visitor Pattern Use Cases
Use Case Explanation

When you have complex object hierarchies and want to


Complex object structures perform operations across them without cluttering the
objects.

Adding operations without When you need to add new functionality frequently to
changing classes unrelated classes but want to avoid modifying their code.

Visiting different types of nodes in Abstract Syntax Trees


Compilers and AST
(AST) for operations like code generation, optimization, or
traversal
type checking.

Serialization / Performing different serialization strategies on diverse object


Deserialization types.

Rendering or processing different UI elements without


UI rendering systems
embedding logic in the elements themselves.

If multiple unrelated operations must be performed on a fixed


Multiple unrelated
set of objects, visitor helps keep those operations clean and
operations
separate.

Visitor Pattern in Spring Boot

Scenario
Imagine a document processing system with different types of documents:

Invoice

Report

We want to:

Generate a summary for each document type.

Generate a detailed report for each document type.

Design Patterns Use Cases (Java And Spring) 258


Using the Visitor pattern, we separate these operations from the document
classes themselves.

Step 1: Define Document Elements (Elements)

package [Link];

public interface Document {


void accept(DocumentVisitor visitor);
}

package [Link];

public class Invoice implements Document {


private double amount;
private String invoiceNumber;

public Invoice(double amount, String invoiceNumber) {


[Link] = amount;
[Link] = invoiceNumber;
}

public double getAmount() { return amount; }


public String getInvoiceNumber() { return invoiceNumber; }

@Override
public void accept(DocumentVisitor visitor) {
[Link](this);
}
}

package [Link];

public class Report implements Document {

Design Patterns Use Cases (Java And Spring) 259


private String title;
private String content;

public Report(String title, String content) {


[Link] = title;
[Link] = content;
}

public String getTitle() { return title; }


public String getContent() { return content; }

@Override
public void accept(DocumentVisitor visitor) {
[Link](this);
}
}

Step 2: Define Visitor Interface

package [Link];

import [Link];
import [Link];

public interface DocumentVisitor {


void visit(Invoice invoice);
void visit(Report report);
}

Step 3: Concrete Visitors

package [Link];

import [Link];

Design Patterns Use Cases (Java And Spring) 260


import [Link];
import [Link];

@Component("summaryVisitor")
public class SummaryVisitor implements DocumentVisitor {

@Override
public void visit(Invoice invoice) {
[Link]("Invoice Summary: Invoice #" + [Link]
mber() + ", Amount: $" + [Link]());
}

@Override
public void visit(Report report) {
[Link]("Report Summary: Title - " + [Link]());
}
}

package [Link];

import [Link];
import [Link];
import [Link];

@Component("detailedVisitor")
public class DetailedVisitor implements DocumentVisitor {

@Override
public void visit(Invoice invoice) {
[Link]("Invoice Detailed Report:\nInvoice Number: " + invoic
[Link]() + "\nAmount Due: $" + [Link]());
}

@Override
public void visit(Report report) {

Design Patterns Use Cases (Java And Spring) 261


[Link]("Report Detailed Content:\nTitle: " + [Link]() +
"\nContent:\n" + [Link]());
}
}

Step 4: Spring Boot Controller to trigger visitors

package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link].*;

@RestController
@RequestMapping("/documents")
public class DocumentController {

@Autowired
@Qualifier("summaryVisitor")
private DocumentVisitor summaryVisitor;

@Autowired
@Qualifier("detailedVisitor")
private DocumentVisitor detailedVisitor;

@GetMapping("/process")
public String processDocument(@RequestParam String type,
@RequestParam String visitorType) {

Document document;

Design Patterns Use Cases (Java And Spring) 262


// Create sample documents based on type
if ("invoice".equalsIgnoreCase(type)) {
document = new Invoice(1500.75, "INV-123");
} else if ("report".equalsIgnoreCase(type)) {
document = new Report("Annual Report", "This is the detailed content
of the annual report...");
} else {
return "Invalid document type";
}

// Choose visitor
DocumentVisitor visitor;
if ("summary".equalsIgnoreCase(visitorType)) {
visitor = summaryVisitor;
} else if ("detailed".equalsIgnoreCase(visitorType)) {
visitor = detailedVisitor;
} else {
return "Invalid visitor type";
}

// Accept visitor
[Link](visitor);

return "Processed " + type + " with " + visitorType + " visitor";
}
}

Step 5: Main Spring Boot Application

package [Link];

import [Link];
import [Link];

@SpringBootApplication

Design Patterns Use Cases (Java And Spring) 263


public class VisitorPatternApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}

Testing the Visitor in Spring Boot


Start the app

Call:

GET [Link]
mary

Console output:

Invoice Summary: Invoice #INV-123, Amount: $1500.75

GET [Link]
led

Console output:

Report Detailed Content:


Title: Annual Report
Content:
This is the detailed content of the annual report...

Summary
Visitor separates operations from document object structure.

Spring beans implement different visitor strategies.

Design Patterns Use Cases (Java And Spring) 264


Controller selects and applies visitors dynamically.

Easy to add new operations by creating new visitors without modifying


documents.

Design Patterns Use Cases (Java And Spring) 265

You might also like