0% found this document useful (0 votes)
2 views42 pages

Design Patterns Java Backend Guide

Uploaded by

Anil Paul
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)
2 views42 pages

Design Patterns Java Backend Guide

Uploaded by

Anil Paul
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 for Java Backend Developers | Zero to Pro + Interview Ready

DESIGN PATTERNS
FOR JAVA BACKEND DEVELOPERS

Zero to Pro • Interview Ready

Creational Patterns Structural Patterns


Singleton • Factory Adapter • Decorator
Builder • Prototype Facade • Proxy
Abstract Factory Composite • Bridge

Behavioral Patterns Architecture & More


Strategy • Observer MVC • Repository
Command • Template SOLID Principles
Chain of Resp. • State Anti-Patterns

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 1: Foundations — Why Design Patterns?


Design patterns are reusable solutions to commonly occurring problems in software design. They
are not finished code you paste in — they are templates describing how to solve a problem in a way
that can be reused across many situations.
For a Java backend developer, patterns appear everywhere: Spring Framework is built on dozens of
them, every enterprise application uses them, and interviewers at every level love to ask about them.

1.1 History & Origin


Design patterns were popularized by the 'Gang of Four' (GoF) — Erich Gamma, Richard Helm,
Ralph Johnson, and John Vlissides — in their 1994 book 'Design Patterns: Elements of Reusable
Object-Oriented Software'. They catalogued 23 patterns still relevant today.

1.2 The Three Pattern Categories


Category Purpose Key Patterns Memory Hook
Creational How objects are created — Singleton, Factory, Builder, CREATION = birth
decouple construction from Prototype, Abstract Factory of objects
use
Structural How objects are composed — Adapter, Decorator, STRUCTURE =
build larger structures from Facade, Proxy, Composite, how parts fit
smaller ones Bridge, Flyweight together
Behavioral How objects communicate — Strategy, Observer, BEHAVIOR = how
algorithms and responsibility Command, Template objects talk
Method, Chain of
Responsibility, State,
Iterator, Mediator, Visitor

1.3 The SOLID Principles — The Foundation


Before patterns, master SOLID. Every design pattern is an application of one or more SOLID
principles.

Principle One-liner Java Violation Example Pattern that helps


S — Single A class should have UserService handles auth, Facade, Command
Responsibility only ONE reason to email, logging AND persistence
change
O— Open for extension, Giant if-else/switch to add new Strategy, Factory
Open/Closed closed for modification payment types
L — Liskov Subclasses must be Rectangle subclass breaks Template Method
Substitution substitutable for their when extended to Square
base class (setWidth side-effect)

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Principle One-liner Java Violation Example Pattern that helps


I — Interface Many specific interfaces Implementing IAnimal with fly() Adapter, Decorator
Segregation > one fat interface for a Dog class
D— Depend on new MySQLRepository() Factory, Dependency
Dependency abstractions, not hardcoded in Service class Injection
Inversion concretions

🎯 Interview Questions
1. What is the difference between a design pattern and an algorithm?
2. Can you explain all five SOLID principles with a Java example?
3. Why are design patterns important? Can't we just write code that works?
4. Which design patterns does the Spring Framework use internally?
5. What is the difference between coupling and cohesion?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 2: Creational Patterns


Creational patterns abstract the instantiation process. They help make a system independent of how
its objects are created, composed, and represented.

2.1 Singleton Pattern


Ensures a class has only ONE instance and provides a global access point to it.

Aspect Detail
Intent One and only one instance, globally accessible
Problem it solves Multiple instances causing inconsistent state (e.g., two DB connection pools)
Real-world Java use Spring @Component beans (default scope), [Link], Logger
factories
When to use Shared resources: DB pools, config, caches, thread pools
When NOT to use Unit-testable code (singletons are hard to mock), when global state is
dangerous

Thread-Safe Singleton (Double-Checked Locking)


public class DatabaseConnectionPool {

// volatile ensures visibility across threads


private static volatile DatabaseConnectionPool instance;
private final List<Connection> pool;

private DatabaseConnectionPool() {
// Private constructor prevents external instantiation
pool = new ArrayList<>();
initializePool();
}

public static DatabaseConnectionPool getInstance() {


if (instance == null) { // First check (no lock)
synchronized ([Link]) {
if (instance == null) { // Second check (with lock)
instance = new DatabaseConnectionPool();
}
}
}
return instance;
}

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

public Connection getConnection() { /* ... */ }


}

Best Practice: Enum Singleton (Joshua Bloch's recommendation)


public enum AppConfig {
INSTANCE; // JVM guarantees single instance — serialization-safe, reflection-safe

private final Properties props = new Properties();

AppConfig() {
// load properties in constructor
try { [Link](getClass().getResourceAsStream('/[Link]')); }
catch (IOException e) { throw new RuntimeException(e); }
}

public String get(String key) { return [Link](key); }


}

// Usage
String dbUrl = [Link]("[Link]");

🌱 Spring Connection
Spring beans are Singletons by default (@Scope("singleton")).
The ApplicationContext IS the singleton container.
Prefer Spring-managed singletons over manual Singleton pattern — they are testable.

🎯 Interview Questions
6. Why is Double-Checked Locking broken without volatile in Java?
7. What are the problems with Singleton pattern? How do you test code that uses it?
8. How does Spring implement the Singleton pattern? How is it different from GoF Singleton?
9. Why is the Enum Singleton considered the best way in Java?
10. How do you break a Singleton using Reflection? How do you prevent it?

2.2 Factory Method Pattern


Defines an interface for creating an object, but lets subclasses decide which class to instantiate.
Delegates the instantiation logic to child classes.

// Step 1: Product interface


public interface NotificationService {

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

void send(String recipient, String message);


}

// Step 2: Concrete products


public class EmailNotification implements NotificationService {
public void send(String recipient, String message) {
[Link]("Sending EMAIL to " + recipient + ": " + message);
}
}

public class SmsNotification implements NotificationService {


public void send(String recipient, String message) {
[Link]("Sending SMS to " + recipient + ": " + message);
}
}

public class PushNotification implements NotificationService {


public void send(String recipient, String message) {
[Link]("Sending PUSH to " + recipient + ": " + message);
}
}

// Step 3: Factory — open for extension (just add new type), no if-else changes
public class NotificationFactory {
public static NotificationService create(String type) {
return switch ([Link]()) {
case "EMAIL" -> new EmailNotification();
case "SMS" -> new SmsNotification();
case "PUSH" -> new PushNotification();
default -> throw new IllegalArgumentException("Unknown type: " + type);
};
}
}

// Step 4: Client code — depends on abstraction, not concrete classes


public class OrderService {
public void processOrder(Order order, String notifType) {
NotificationService notif = [Link](notifType);
[Link]([Link](), "Your order is confirmed!");
}
}

Abstract Factory — Factory of Factories

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Creates families of related objects without specifying concrete classes. Classic example: UI toolkit
that must support multiple themes/OS styles.
// Abstract Factory for database access — supports MySQL and PostgreSQL
public interface DbFactory {
UserRepository createUserRepository();
OrderRepository createOrderRepository();
}

public class MySQLFactory implements DbFactory {


public UserRepository createUserRepository() { return new MySQLUserRepo(); }
public OrderRepository createOrderRepository() { return new MySQLOrderRepo(); }
}

public class PostgreSQLFactory implements DbFactory {


public UserRepository createUserRepository() { return new PgUserRepo(); }
public OrderRepository createOrderRepository() { return new PgOrderRepo(); }
}

// Client — completely unaware of which DB is used


public class AppBootstrap {
public static DbFactory getFactory(String db) {
return [Link]("mysql") ? new MySQLFactory() : new PostgreSQLFactory();
}
}

🎯 Interview Questions
11. What is the difference between Factory Method and Abstract Factory?
12. How does the Spring BeanFactory / ApplicationContext use the Factory pattern?
13. When would you use Factory over 'new'? What are the advantages?
14. How would you add a new notification type to a factory without modifying existing code?

2.3 Builder Pattern


Separates the construction of a complex object from its representation. Essential for objects with
many optional parameters — avoids the 'telescoping constructor' anti-pattern.

// Without Builder — Telescoping Constructor Anti-Pattern (avoid this)


new HttpRequest("GET", url, null, null, null, 30, false, null); // What are all these
nulls?!

// With Builder — readable, fluent, immutable result


public class HttpRequest {
private final String method;

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

private final String url;


private final Map<String, String> headers;
private final String body;
private final int timeoutSeconds;
private final boolean followRedirects;

private HttpRequest(Builder builder) {


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

public static class Builder {


private final String method; // required
private final String url; // required
private Map<String, String> headers = new HashMap<>();
private String body = null;
private int timeoutSeconds = 30;
private boolean followRedirects = true;

public Builder(String method, String url) { // Required params in constructor


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

public Builder header(String key, String value) {


[Link](key, value);
return this; // Fluent API — return 'this' for chaining
}

public Builder body(String body) { [Link] = body; return


this; }
public Builder timeout(int seconds) { [Link] =
seconds; return this; }
public Builder followRedirects(boolean follow) { [Link] =
follow; return this; }

public HttpRequest build() {


// Validate before building
if (body != null && [Link]("GET"))
throw new IllegalStateException("GET requests cannot have a body");
return new HttpRequest(this);

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

}
}
}

// Usage — crystal clear what each parameter means


HttpRequest request = new [Link]("POST", "[Link]
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + token)
.body("{ \"name\": \"Alice\" }")
.timeout(10)
.build();

💡 Lombok @Builder
@Builder annotation generates the builder automatically:
@Data @Builder @AllArgsConstructor @NoArgsConstructor
public class UserDto { private String name; private String email; private int age; }

// Usage: [Link]().name("Alice").email("a@[Link]").age(30).build();

🎯 Interview Questions
15. What problem does the Builder pattern solve? What is the 'telescoping constructor' problem?
16. How does the Builder pattern differ from the Factory pattern?
17. How does Lombok's @Builder work under the hood?
18. How would you make a Builder thread-safe?

2.4 Prototype Pattern


Creates new objects by cloning an existing object (the prototype). Useful when object creation is
expensive or complex.
// Deep clone example for a game character
public class GameCharacter implements Cloneable {
private String name;
private List<String> inventory; // mutable — needs deep copy
private Weapon weapon;

@Override
public GameCharacter clone() {
try {
GameCharacter clone = (GameCharacter) [Link](); // shallow copy
[Link] = new ArrayList<>([Link]); // deep copy list
[Link] = [Link](); // deep copy object
return clone;

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

} catch (CloneNotSupportedException e) {
throw new AssertionError("Should never happen", e);
}
}
}

// Prototype Registry — store and clone named prototypes


public class CharacterRegistry {
private final Map<String, GameCharacter> registry = new HashMap<>();

public void register(String key, GameCharacter character) {


[Link](key, character);
}

public GameCharacter get(String key) {


return [Link](key).clone(); // Always return a clone
}
}

🎯 Interview Questions
19. What is the difference between shallow copy and deep copy in Java?
20. When would you prefer Prototype over Factory?
21. Why is Java's Cloneable interface considered broken? What are the alternatives?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 3: Structural Patterns


Structural patterns explain how to assemble objects and classes into larger structures, while keeping
these structures flexible and efficient.

3.1 Adapter Pattern


Converts the interface of a class into another interface that clients expect. Enables classes with
incompatible interfaces to work together. Also called 'Wrapper'.

// Scenario: Our app uses UserProfile, but a legacy system returns LegacyUser

// Target interface — what our code expects


public interface UserProfile {
String getFullName();
String getEmailAddress();
String getPhoneNumber();
}

// Adaptee — legacy class we CANNOT modify


public class LegacyUser {
public String getFirstName() { return "John"; }
public String getLastName() { return "Doe"; }
public String getEmail() { return "john@[Link]"; }
public String getMobileNo() { return "+1-555-0100"; }
}

// Object Adapter — wraps the adaptee


public class LegacyUserAdapter implements UserProfile {
private final LegacyUser legacyUser;

public LegacyUserAdapter(LegacyUser legacyUser) {


[Link] = legacyUser;
}

@Override public String getFullName() { return [Link]() + " "


+ [Link](); }
@Override public String getEmailAddress() { return [Link](); }
@Override public String getPhoneNumber() { return [Link](); }
}

// Client code — unchanged, works with new and legacy users


public void sendWelcomeEmail(UserProfile user) {
[Link]([Link](), "Welcome " + [Link]());

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Using the adapter


LegacyUser legacyUser = [Link](id);
sendWelcomeEmail(new LegacyUserAdapter(legacyUser)); // Works seamlessly!

🔌 Real-world Java Adapters


• [Link]() — adapts an array to a List interface
• InputStreamReader — adapts InputStream (bytes) to Reader (characters)
• Spring HandlerAdapter — adapts different controller types to a uniform handler
• JDBC RowMapper — adapts ResultSet rows to domain objects

🎯 Interview Questions
22. What is the difference between Adapter and Facade pattern?
23. What is the difference between Class Adapter and Object Adapter in Java?
24. Give a real-world example of the Adapter pattern in Java or Spring.
25. When would you use Adapter vs rewriting the existing class?

3.2 Decorator Pattern


Attaches additional responsibilities to an object dynamically. Provides a flexible alternative to
subclassing for extending functionality. Java I/O is the textbook example.

// Scenario: Coffee ordering system with dynamic pricing/description

// Component interface
public interface Coffee {
String getDescription();
double getCost();
}

// Concrete Component
public class Espresso implements Coffee {
public String getDescription() { return "Espresso"; }
public double getCost() { return 1.99; }
}

// Abstract Decorator — wraps a Coffee and implements Coffee


public abstract class CoffeeDecorator implements Coffee {
protected final Coffee coffee; // wraps the component
public CoffeeDecorator(Coffee coffee) { [Link] = coffee; }
}

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Concrete Decorators
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) { super(coffee); }
public String getDescription() { return [Link]() + ", Milk"; }
public double getCost() { return [Link]() + 0.25; }
}

public class VanillaDecorator extends CoffeeDecorator {


public VanillaDecorator(Coffee coffee) { super(coffee); }
public String getDescription() { return [Link]() + ", Vanilla"; }
public double getCost() { return [Link]() + 0.50; }
}

public class WhipDecorator extends CoffeeDecorator {


public WhipDecorator(Coffee coffee) { super(coffee); }
public String getDescription() { return [Link]() + ", Whip"; }
public double getCost() { return [Link]() + 0.75; }
}

// Usage — compose at runtime!


Coffee order = new Espresso();
order = new MilkDecorator(order);
order = new VanillaDecorator(order);
order = new WhipDecorator(order);
// Espresso, Milk, Vanilla, Whip — $3.49
[Link]([Link]() + " — $" + [Link]());

☕ Java I/O — The Classic Decorator Example


new BufferedReader(new InputStreamReader(new FileInputStream("[Link]")))

FileInputStream — reads bytes from a file


InputStreamReader — DECORATES with character conversion
BufferedReader — DECORATES with buffering and readLine()

Spring AOP (@Transactional, @Cacheable) uses the Decorator/Proxy pattern.

🎯 Interview Questions
26. How does Java I/O use the Decorator pattern?
27. What is the difference between Decorator and Inheritance? When would you choose each?
28. How does Spring AOP relate to the Decorator pattern?
29. What is the difference between Decorator and Proxy pattern?
30. Can you have too many decorators? What are the downsides?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

3.3 Facade Pattern


Provides a simplified interface to a complex subsystem. Hides the complexity; client talks to one
simple class instead of many complex ones.
// Complex subsystem — multiple services
public class OrderFacade {
private final InventoryService inventory;
private final PaymentService payment;
private final ShippingService shipping;
private final NotificationService notif;
private final AuditService audit;

// Constructor injection (Spring @Service would autowire these)


public OrderFacade(InventoryService inventory, PaymentService payment,
ShippingService shipping, NotificationService notif,
AuditService audit) { /* assign */ }

// ONE simple method hides orchestration of 5 services


public OrderResult placeOrder(Cart cart, PaymentDetails payment) {
// 1. Check stock
if (![Link]([Link]()))
return [Link]("Items out of stock");

// 2. Process payment
PaymentResult payResult = [Link](payment, [Link]());
if (![Link]())
return [Link]("Payment failed");

// 3. Reserve inventory
[Link]([Link]());

// 4. Create shipment
Shipment shipment = [Link](cart, [Link]());

// 5. Notify customer
[Link]([Link](), shipment);

// 6. Audit
[Link]("ORDER_PLACED", [Link]().getId());

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

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Client — calls ONE method instead of managing 5 services


OrderResult result = [Link](cart, paymentDetails);

🎯 Interview Questions
31. What is the difference between Facade and Adapter?
32. How is the Spring JdbcTemplate an example of the Facade pattern?
33. Can a Facade violate the Single Responsibility Principle? How do you keep it clean?
34. How does Facade relate to microservices API Gateway pattern?

3.4 Proxy Pattern


Provides a surrogate or placeholder for another object to control access to it. There are three main
types of proxy in Java backend development:

Proxy Type Purpose Java / Spring Example


Virtual Proxy Lazy initialization — defer Hibernate lazy-loading of @OneToMany
expensive object creation collections
Protection Proxy Access control — check Spring Security method security
permissions before delegating (@PreAuthorize)
Remote Proxy Represent a remote object RMI stubs, Feign clients in Spring Cloud
locally
Caching Proxy Cache results and return cached Spring @Cacheable annotation
if available
Logging Proxy Log calls transparently Spring AOP @Around advice

// Manual Caching Proxy Example


public interface UserRepository {
User findById(Long id);
}

public class DatabaseUserRepository implements UserRepository {


public User findById(Long id) {
// Expensive DB call
return [Link]("SELECT * FROM users WHERE id=?", ...);
}
}

public class CachingUserRepositoryProxy implements UserRepository {


private final UserRepository delegate; // The real object
private final Map<Long, User> cache = new ConcurrentHashMap<>();

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

public CachingUserRepositoryProxy(UserRepository delegate) {


[Link] = delegate;
}

@Override
public User findById(Long id) {
return [Link](id, key -> [Link](key));
}
}

// Spring does this transparently with @Cacheable:


@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User findById(Long id) { return [Link](id); }
}

🎯 Interview Questions
35. How does Spring AOP use the Proxy pattern? What is a JDK Dynamic Proxy vs CGLIB
proxy?
36. What is the difference between Proxy and Decorator pattern?
37. How does Hibernate use the Virtual Proxy for lazy loading?
38. How does @Transactional work internally in Spring? (Hint: it's a Proxy)
39. What happens when you call a @Transactional method from within the same class? Why?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 4: Behavioral Patterns


Behavioral patterns are concerned with algorithms and the assignment of responsibilities between
objects. They describe not just patterns of objects or classes but also the patterns of communication
between them.

4.1 Strategy Pattern


Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Lets the
algorithm vary independently from clients that use it. The most commonly asked pattern in Java
interviews.

// Scenario: E-commerce discount calculation — varies by customer type

// Strategy interface
@FunctionalInterface // Can be implemented as a Lambda!
public interface DiscountStrategy {
double apply(double originalPrice);
}

// Concrete strategies
public class RegularCustomerDiscount implements DiscountStrategy {
public double apply(double price) { return price; } // No discount
}

public class PremiumCustomerDiscount implements DiscountStrategy {


public double apply(double price) { return price * 0.90; } // 10% off
}

public class LoyaltyCustomerDiscount implements DiscountStrategy {


private final int loyaltyYears;
public LoyaltyCustomerDiscount(int years) { [Link] = years; }
public double apply(double price) {
double discountPct = [Link](0.30, loyaltyYears * 0.05); // Up to 30%
return price * (1 - discountPct);
}
}

// Context — uses a strategy


public class PricingEngine {
private DiscountStrategy strategy;

public PricingEngine(DiscountStrategy strategy) {


[Link] = strategy;

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Strategy can be swapped at runtime!


public void setStrategy(DiscountStrategy strategy) {
[Link] = strategy;
}

public double calculateFinalPrice(double basePrice) {


return [Link](basePrice);
}
}

// Usage — policy selected at runtime based on customer type


DiscountStrategy strategy = switch ([Link]()) {
case REGULAR -> new RegularCustomerDiscount();
case PREMIUM -> new PremiumCustomerDiscount();
case LOYAL -> new LoyaltyCustomerDiscount([Link]());
};

// With Java 8+: Lambda instead of class (works because @FunctionalInterface)


DiscountStrategy vipStrategy = price -> price * 0.70; // 30% VIP discount

PricingEngine engine = new PricingEngine(strategy);


double finalPrice = [Link]([Link]());

🎯 Interview Questions
40. How does Strategy pattern relate to the Open/Closed Principle?
41. What is the difference between Strategy and State pattern?
42. How do Java 8 lambdas change how we implement Strategy pattern?
43. Give a real-world Spring example of the Strategy pattern.
44. Strategy vs Template Method — when would you choose each?

4.2 Observer Pattern


Defines a one-to-many dependency between objects so that when one object changes state, all its
dependents are notified and updated automatically. Foundation of event-driven architecture.

// Modern Java Observer using Spring Events

// Step 1: Event (the 'thing that happened')


public class OrderPlacedEvent extends ApplicationEvent {
private final Order order;

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

public OrderPlacedEvent(Object source, Order order) {


super(source);
[Link] = order;
}
public Order getOrder() { return order; }
}

// Step 2: Publisher (Subject/Observable)


@Service
public class OrderService {
@Autowired private ApplicationEventPublisher publisher;
@Autowired private OrderRepository repository;

public Order placeOrder(Cart cart) {


Order order = [Link](new Order(cart));
[Link](new OrderPlacedEvent(this, order)); // Fire event
return order;
}
}

// Step 3: Observers (Listeners) — each handles its own concern


@Component
public class EmailNotificationListener {
@EventListener
public void onOrderPlaced(OrderPlacedEvent event) {
[Link]([Link]());
}
}

@Component
public class InventoryListener {
@EventListener
@Async // Non-blocking — runs in separate thread
public void onOrderPlaced(OrderPlacedEvent event) {
[Link]([Link]().getItems());
}
}

@Component
public class AnalyticsListener {
@EventListener
public void onOrderPlaced(OrderPlacedEvent event) {
[Link]("order_placed", [Link]().getId());
}

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Adding a new observer (e.g., loyalty points) = just add a new @EventListener
// NO changes to OrderService needed — Open/Closed Principle!

🎯 Interview Questions
45. What is the difference between push model and pull model in Observer pattern?
46. How does Spring ApplicationEventPublisher implement the Observer pattern?
47. What is the relationship between Observer pattern and reactive programming (RxJava)?
48. What are the memory leak risks with Observer pattern in Java?
49. How does Kafka/messaging relate to the Observer pattern at a distributed level?

4.3 Command Pattern


Encapsulates a request as an object, letting you parameterize clients with different requests, queue
or log requests, and support undoable operations.

// Command interface
public interface Command {
void execute();
void undo(); // Optional but powerful
}

// Concrete Commands
public class TransferMoneyCommand implements Command {
private final BankAccount from;
private final BankAccount to;
private final BigDecimal amount;
private boolean executed = false;

public TransferMoneyCommand(BankAccount from, BankAccount to, BigDecimal amount) {


[Link] = from; [Link] = to; [Link] = amount;
}

@Override
public void execute() {
[Link](amount);
[Link](amount);
[Link] = true;
}

@Override

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

public void undo() {


if (!executed) throw new IllegalStateException("Not yet executed");
[Link](amount);
[Link](amount);
}
}

// Command Processor (Invoker) — with queue and undo history


public class CommandProcessor {
private final Deque<Command> history = new ArrayDeque<>();
private final BlockingQueue<Command> queue = new LinkedBlockingQueue<>();

public void submit(Command cmd) {


[Link](cmd); // Queue for async processing
}

public void executeNext() {


Command cmd = [Link]();
if (cmd != null) {
[Link]();
[Link](cmd); // Save for undo
}
}

public void undoLast() {


if (![Link]()) {
[Link]().undo();
}
}
}

🎯 Interview Questions
50. What are the four participants in the Command pattern?
51. How does the Command pattern support undo/redo functionality?
52. How does Spring Batch use the Command pattern?
53. How would you use the Command pattern to implement a task queue / job scheduler?

4.4 Template Method Pattern


Defines the skeleton of an algorithm in a base class, deferring some steps to subclasses.
Subclasses can override specific steps without changing the algorithm's structure. Spring uses this
extensively.
// Abstract class defines the algorithm skeleton

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

public abstract class DataExporter {

// Template method — defines the invariant steps


public final void export(String destination) { // final = cannot be overridden
List<Object> data = fetchData(); // Step 1: get data
List<Object> filtered = filterData(data); // Step 2: filter
String formatted = formatData(filtered); // Step 3: format (varies by type)
writeToDestination(formatted, destination); // Step 4: write
cleanup(); // Step 5: cleanup (hook)
}

protected abstract List<Object> fetchData(); // Must be implemented


protected abstract String formatData(List<Object> data); // Must implement

// Default implementations — can be overridden if needed


protected List<Object> filterData(List<Object> data) {
return data; // Default: no filtering
}

protected void writeToDestination(String data, String dest) {


[Link]([Link](dest), data); // Default: write to file
}

protected void cleanup() { } // Hook method — optional override


}

// Concrete implementation — CSV exporter


public class CsvExporter extends DataExporter {
@Override
protected List<Object> fetchData() { return [Link](); }

@Override
protected String formatData(List<Object> data) {
return [Link]().map(Object::toString).collect([Link](",\n"));
}
}

// Spring's [Link]() uses Template Method:


// JdbcTemplate defines the SQL execution flow
// You provide the RowMapper to customize the result mapping step

🎯 Interview Questions
54. What is the Hollywood Principle and how does Template Method implement it?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

55. What is the difference between Template Method and Strategy? When to use each?
56. How does Spring JdbcTemplate use the Template Method pattern?
57. What is a 'hook method' in Template Method pattern?

4.5 Chain of Responsibility Pattern


Passes a request along a chain of handlers. Each handler decides to process the request or pass it
to the next handler in the chain. Used heavily in middleware and filter pipelines.
// Handler interface
public abstract class RequestHandler {
private RequestHandler next;

public RequestHandler setNext(RequestHandler next) {


[Link] = next;
return next; // Enables fluent chaining: [Link](rateLimit).setNext(log)
}

public abstract void handle(HttpRequest request);

protected void passToNext(HttpRequest request) {


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

// Concrete Handlers
public class AuthenticationHandler extends RequestHandler {
public void handle(HttpRequest request) {
if (![Link]()) {
[Link](401, "Unauthorized");
return; // Stop the chain
}
passToNext(request);
}
}

public class RateLimitHandler extends RequestHandler {


public void handle(HttpRequest request) {
if (isRateLimitExceeded([Link]())) {
[Link](429, "Too Many Requests");
return;
}
passToNext(request);
}

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

public class LoggingHandler extends RequestHandler {


public void handle(HttpRequest request) {
[Link]("Processing: " + [Link]());
passToNext(request); // Always passes — just observes
[Link]("Completed: " + [Link]());
}
}

// Building the chain


RequestHandler auth = new AuthenticationHandler();
RequestHandler rateLimit = new RateLimitHandler();
RequestHandler logging = new LoggingHandler();

[Link](rateLimit).setNext(logging);

// Servlet Filters, Spring Security FilterChain = Chain of Responsibility

🎯 Interview Questions
58. How does the Java Servlet Filter chain implement Chain of Responsibility?
59. How does Spring Security's FilterChainProxy use this pattern?
60. What is the difference between Chain of Responsibility and Decorator?
61. When should a handler stop the chain vs pass it along?

4.6 State Pattern


Allows an object to alter its behavior when its internal state changes. The object will appear to
change its class. Eliminates large if-else / switch statements based on state.
// Order state machine using State pattern
public interface OrderState {
void confirm(OrderContext context);
void ship(OrderContext context);
void deliver(OrderContext context);
void cancel(OrderContext context);
String getStateName();
}

// Concrete States — each state only allows valid transitions


public class PendingState implements OrderState {
public void confirm(OrderContext ctx) {
[Link]("Order confirmed!");
[Link](new ConfirmedState());

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

}
public void ship(OrderContext ctx) { throw new IllegalStateException("Confirm
first!"); }
public void deliver(OrderContext ctx) { throw new IllegalStateException("Not
shipped yet!"); }
public void cancel(OrderContext ctx) { [Link](new CancelledState()); }
public String getStateName() { return "PENDING"; }
}

public class ConfirmedState implements OrderState {


public void confirm(OrderContext ctx) { throw new IllegalStateException("Already
confirmed!"); }
public void ship(OrderContext ctx) { [Link](new ShippedState()); }
public void deliver(OrderContext ctx) { throw new IllegalStateException("Not
shipped yet!"); }
public void cancel(OrderContext ctx) { [Link](new CancelledState()); }
public String getStateName() { return "CONFIRMED"; }
}

// Context — delegates to current state


public class OrderContext {
private OrderState currentState = new PendingState();

public void setState(OrderState state) { [Link] = state; }


public void confirm() { [Link](this); }
public void ship() { [Link](this); }
public void deliver() { [Link](this); }
public void cancel() { [Link](this); }
public String getStatus() { return [Link](); }
}

🎯 Interview Questions
62. What is the difference between State and Strategy pattern?
63. How would you persist the state of a State Machine to a database?
64. How does Spring State Machine library implement this pattern?
65. When is a state machine better than a boolean flag / enum + if-else?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 5: Architectural Patterns in Spring


Beyond the 23 GoF patterns, modern Java backend development relies on architectural and
enterprise patterns. These are staples of Spring Boot applications and senior-level interview topics.

5.1 Repository Pattern


Abstracts the data layer, providing a collection-like interface for accessing domain objects.
Decouples business logic from data access technology.
// Domain object
public class Product {
private Long id;
private String name;
private BigDecimal price;
private int stockQuantity;
}

// Repository interface — defines what operations are needed (domain language)


public interface ProductRepository {
Optional<Product> findById(Long id);
List<Product> findByCategory(String category);
List<Product> findLowStockProducts(int threshold);
Product save(Product product);
void delete(Long id);
}

// JPA implementation
@Repository
public class JpaProductRepository implements ProductRepository {
@PersistenceContext
private EntityManager em;

public Optional<Product> findById(Long id) {


return [Link]([Link]([Link], id));
}

public List<Product> findLowStockProducts(int threshold) {


return [Link](
"SELECT p FROM Product p WHERE [Link] < :threshold",
[Link])
.setParameter("threshold", threshold)
.getResultList();
}
// ... other methods

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Spring Data JPA — auto-implements common methods


public interface ProductJpaRepository extends JpaRepository<Product, Long> {
List<Product> findByCategory(String category); // Auto-
generated!
@Query("SELECT p FROM Product p WHERE [Link] < :t")
List<Product> findLowStock(@Param("t") int threshold); // Custom JPQL
}

// Service — depends on abstraction, not implementation


@Service
public class InventoryService {
private final ProductRepository products; // Interface — swappable!

public InventoryService(ProductRepository products) {


[Link] = products;
}

public List<Product> getLowStockAlert() {


return [Link](10);
}
}

🎯 Interview Questions
66. What is the difference between Repository pattern and DAO (Data Access Object) pattern?
67. How does Spring Data JPA's JpaRepository implement the Repository pattern?
68. Why should a repository interface use domain language, not SQL/persistence language?
69. How do you test a service that uses a repository without a real database?

5.2 MVC Pattern in Spring Boot


Model-View-Controller separates an application into three interconnected components. In REST
APIs, the 'View' is the JSON response.
// Model — the domain/data
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String username;
private String email;
}

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// Controller (C) — handles HTTP, maps requests to service calls


@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;

public UserController(UserService userService) {


[Link] = userService;
}

@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
return [Link](id)
.map(ResponseEntity::ok)
.orElse([Link]().build());
}

@PostMapping
@ResponseStatus([Link])
public UserDto createUser(@Valid @RequestBody CreateUserRequest request) {
return [Link](request);
}
}

// Service (part of Model in Spring MVC) — business logic


@Service
@Transactional
public class UserService {
private final UserRepository repository;
private final UserMapper mapper;

public Optional<UserDto> findById(Long id) {


return [Link](id).map(mapper::toDto);
}

public UserDto create(CreateUserRequest req) {


User user = [Link](req);
return [Link]([Link](user));
}
}

5.3 Dependency Injection — Spring's Core Pattern

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

DI is an implementation of the Dependency Inversion Principle. Objects receive their dependencies


from an external source rather than creating them. Spring IoC Container manages this.
// Three types of injection in Spring

// 1. Constructor Injection (PREFERRED — immutable, testable)


@Service
public class OrderService {
private final PaymentService paymentService;
private final InventoryService inventoryService;
private final OrderRepository repository;

// Spring auto-detects single constructor — @Autowired optional


public OrderService(PaymentService payment, InventoryService inventory,
OrderRepository repo) {
[Link] = payment;
[Link] = inventory;
[Link] = repo;
}
}

// 2. Setter Injection (for optional dependencies)


@Service
public class ReportService {
private CacheService cacheService; // Optional

@Autowired(required = false)
public void setCacheService(CacheService cache) {
[Link] = cache;
}
}

// 3. Field Injection (AVOID in production — hard to test)


@Service
public class BadService {
@Autowired // ← Avoid this in production code
private UserRepository repo;
}

// Why constructor injection is best — testable without Spring:


class OrderServiceTest {
@Test void testOrder() {
OrderService service = new OrderService(
mock([Link]),
mock([Link]),

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

mock([Link])
);
// No Spring context needed!
}
}

🎯 Interview Questions
70. What are the three types of Dependency Injection? Which does Spring recommend and
why?
71. What is the difference between IoC Container and Dependency Injection?
72. Why is field injection (@Autowired on field) considered bad practice?
73. What is circular dependency in Spring? How do you resolve it?
74. What is the difference between @Component, @Service, @Repository, and @Controller?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 6: Design Patterns Inside Spring


Framework
Spring Boot is essentially a framework built on top of design patterns. Understanding which patterns
power which Spring features sets you apart in interviews.

Spring Feature Design Pattern(s) How it uses the pattern


Spring IoC Container Factory, Singleton BeanFactory creates beans; beans default to
Singleton scope
@Transactional Proxy (AOP) Spring wraps your bean in a JDK/CGLIB
proxy that adds transaction logic
@Cacheable Proxy, Decorator Proxy intercepts method call, returns cached
value if present
ApplicationEventPublisher Observer Publish events; @EventListener methods are
the observers
JdbcTemplate / RestTemplate Template Method Skeleton algorithm defined; you provide
RowMapper/ResponseExtractor
Spring Security FilterChain Chain of Responsibility Request passes through ordered security
filters
HandlerMapping / Strategy Different strategies for mapping and handling
HandlerAdapter requests
@Conditional / @Profile Strategy Select implementation based on runtime
condition
Spring MVC Front Controller Single entry point dispatches to appropriate
DispatcherServlet handlers
@Component / Factory ApplicationContext acts as a factory for
@Configuration beans
Hibernate Lazy Loading Virtual Proxy Proxy object loads data only when accessed
Spring Data Repositories Repository, Proxy Interface + dynamic proxy auto-implements
CRUD

6.1 How @Transactional Works Internally


This is one of the most popular senior interview questions. The answer is: Proxy + AOP.
// Your code
@Service
public class TransferService {
@Transactional // You write this
public void transfer(Long fromId, Long toId, BigDecimal amount) {
[Link](fromId, amount);
[Link](toId, amount);
}

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// What Spring generates at runtime (simplified proxy code):


public class TransferService$$SpringCGLIBProxy extends TransferService {
@Override
public void transfer(Long fromId, Long toId, BigDecimal amount) {
TransactionStatus tx = [Link](new DefaultTransactionDef());
try {
[Link](fromId, toId, amount); // Call your actual code
[Link](tx);
} catch (RuntimeException e) {
[Link](tx);
throw e;
}
}
}

// ⚠️ The famous self-invocation pitfall:


@Service
public class OrderService {
@Transactional
public void createOrder() { /* starts TX */ }

public void processBatch() {


[Link](); // ← Calls through 'this', NOT through proxy!
// @Transactional is IGNORED here!
}
}

// Fix: Inject self, or refactor to separate @Service class

6.2 Strategy Pattern in Spring — @Qualifier and Multiple


Implementations
// Multiple implementations of same interface
public interface PaymentProcessor {
PaymentResult process(Payment payment);
String supports();
}

@Service
public class StripeProcessor implements PaymentProcessor {
public PaymentResult process(Payment p) { /* Stripe API call */ }
public String supports() { return "STRIPE"; }

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

@Service
public class PayPalProcessor implements PaymentProcessor {
public PaymentResult process(Payment p) { /* PayPal API call */ }
public String supports() { return "PAYPAL"; }
}

// Strategy selector using all registered implementations


@Service
public class PaymentService {
private final Map<String, PaymentProcessor> processors;

// Spring injects ALL implementations of PaymentProcessor


public PaymentService(List<PaymentProcessor> processorList) {
[Link] = [Link]()
.collect([Link](PaymentProcessor::supports, p -> p));
}

public PaymentResult processPayment(Payment payment) {


String method = [Link]();
PaymentProcessor processor = [Link](method);
if (processor == null) throw new IllegalArgumentException("Unknown: " +
method);
return [Link](payment);
}
}
// Adding a new payment method = add a new @Service class. Zero existing code changes.

🎯 Interview Questions
75. How does Spring use the Proxy pattern for @Transactional? What is the self-invocation
problem?
76. What is the difference between JDK Dynamic Proxy and CGLIB proxy in Spring?
77. Explain how you would implement a plugin/extension system in Spring using Strategy.
78. How does Spring's DispatcherServlet implement the Front Controller pattern?
79. If you add a new payment type to an existing system, which Spring + pattern combination
would you use and why?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 7: Anti-Patterns — What NOT to Do


Anti-patterns are common responses to recurring problems that appear reasonable but actually
make things worse. Recognizing them is as valuable as knowing the patterns themselves — and
interviewers love to ask about them.

Anti-Pattern What it is The Fix


God Class / Blob One class does everything — 3000- Split by Single Responsibility; use
line UserService smaller, focused services
Anemic Domain Model Domain objects are just data bags Move behavior into domain objects (rich
(getters/setters only), all logic in domain model)
services
Spaghetti Code No clear structure; methods calling Apply MVC/layered architecture; clear
methods in random order separation of concerns
Copy-Paste Duplicating code instead of DRY principle; extract to shared methods
Programming extracting abstractions / utilities
Magic Numbers / Raw numbers/strings in code Named constants, enums, or config
Strings (status == 3, type == "A") values
Premature Optimization Optimizing before measuring Measure first (profiler), then optimize the
performance problems bottleneck
Shotgun Surgery Changing one feature requires Improve cohesion; group related things
changing many unrelated classes together
Feature Envy A method uses data from another Move the method to the class it envies
class more than its own

7.1 Anemic Domain Model — The Most Common Java Anti-Pattern


// ❌ ANEMIC DOMAIN MODEL — domain objects have no behavior
public class Order {
private Long id;
private OrderStatus status;
private List<OrderItem> items;
private BigDecimal totalAmount;
// Only getters and setters — no logic whatsoever
}

// All business logic dumped into a service (fat service, dumb model)
public class OrderService {
public void cancelOrder(Order order) {
if ([Link]() == [Link])
throw new IllegalStateException("Cannot cancel delivered order");
if ([Link]() == [Link])
throw new IllegalStateException("Already cancelled");
[Link]([Link]);

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

// ... etc — this logic belongs to Order, not here!


}
}

// ✅ RICH DOMAIN MODEL — behavior belongs to the domain object


public class Order {
private Long id;
private OrderStatus status;
private List<OrderItem> items;

// Business logic lives with the data it needs — proper OOP!


public void cancel() {
if ([Link] == [Link])
throw new IllegalStateException("Cannot cancel delivered order");
if ([Link] == [Link])
throw new IllegalStateException("Already cancelled");
[Link] = [Link];
}

public BigDecimal calculateTotal() {


return [Link]().map(OrderItem::getSubtotal).reduce([Link],
BigDecimal::add);
}

public boolean isEligibleForDiscount() {


return calculateTotal().compareTo(new BigDecimal("100")) > 0;
}
}

// Service becomes thin — orchestrates, doesn't implement business rules


public class OrderService {
public void cancelOrder(Long orderId) {
Order order = [Link](orderId).orElseThrow();
[Link](); // Business rule inside the domain object
[Link](order);
}
}

🎯 Interview Questions
80. What is the Anemic Domain Model anti-pattern? Why is it considered bad?
81. What is the God Class / Blob anti-pattern? How do you refactor it?
82. What is the difference between a design pattern and an anti-pattern?
83. Can a design pattern become an anti-pattern? Give an example.

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

84. What is 'over-engineering' and how do you avoid it?

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 8: Interview Masterclass


This chapter consolidates everything from an interview perspective. Use this as your final
preparation checklist.

8.1 Pattern Recognition — Spot the Pattern in the Question


If the interviewer says... Think...
'only one instance', 'global state', 'shared Singleton
resource'
'create object without specifying class', Factory / Abstract Factory
'decouple creation'
'many optional parameters', 'fluent API', Builder
'immutable object'
'add behavior without changing class', 'wrap Decorator
dynamically'
'incompatible interfaces', 'legacy system Adapter
integration'
'simplify complex subsystem', 'hide complexity' Facade
'control access', 'lazy load', 'AOP', Proxy
'@Transactional'
'swap algorithm at runtime', 'multiple Strategy
implementations'
'notify dependents when state changes', Observer
'event-driven'
'undo/redo', 'task queue', 'audit log' Command
'fixed algorithm skeleton', 'subclass fills in Template Method
steps'
'request through pipeline', 'filters', 'middleware' Chain of Responsibility
'valid state transitions', 'state machine', 'entity State
lifecycle'

8.2 The Perfect Answer Framework (STAR for Patterns)

🎤 SCIP — How to structure a pattern answer


S — Situation: 'The problem arises when...'
C — Concept: 'The [Pattern Name] pattern addresses this by...'
I — Implementation: Walk through your Java code example
P — Production use: 'In Spring/real projects, this appears as...'

Example for Strategy:


S: 'When we have multiple algorithms that can be swapped, using if-else chains violates OCP'

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

C: 'Strategy encapsulates each algorithm in its own class behind a common interface'
I: [Show DiscountStrategy code]
P: 'Spring uses this for its PaymentProcessor, AuthenticationProvider — anywhere multiple
implementations of an interface can be selected at runtime'

8.3 Top 25 Design Pattern Interview Questions with Key Answers

Singleton
Question Key Points in Answer
Why is volatile needed in DCL Singleton? Without volatile, JVM may publish partially-constructed
object; volatile prevents instruction reordering
How to prevent Singleton from Reflection? Check in constructor: if(instance!=null) throw new Exception.
Enum Singleton handles this automatically
Spring beans vs GoF Singleton? Spring Singleton is per-container, not per-JVM. GoF is per-
ClassLoader. Spring's are testable/mockable

Factory & Builder


Question Key Points in Answer
Factory vs Abstract Factory vs Builder? Factory: creates one product type. Abstract Factory: creates
families of related products. Builder: constructs one complex
object step by step
Why is Builder better than telescoping Readability, validation on build(), named parameters feel,
constructor? optional params easy, immutable result

Proxy & Decorator


Question Key Points in Answer
Difference between Proxy and Decorator? Proxy controls ACCESS to the object (same interface, wraps
the REAL object). Decorator ADDS new behavior (wraps to
extend, not control)
JDK Dynamic Proxy vs CGLIB? JDK: requires interface, uses [Link]. CGLIB:
subclasses the target class, no interface needed. Spring
uses JDK if interface exists, CGLIB otherwise
@Transactional self-invocation problem? Calling @Transactional method from within the same class
bypasses the proxy — transaction is not started. Fix: inject
self or separate into another bean

Strategy & Observer

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Question Key Points in Answer


Strategy vs Template Method? Strategy: algorithm varies, selected at runtime via
composition. Template Method: algorithm skeleton fixed in
superclass, steps customized by subclasses via inheritance
Strategy vs State? Both look similar. Key difference: Strategy is chosen by the
client and usually doesn't change. State changes
automatically based on the object's internal transitions
Observer memory leaks? If listeners are not deregistered, the subject holds a strong
reference preventing GC. Use WeakReference listeners or
explicitly remove listeners

8.4 Scenario-Based Questions

📝 Scenario 1: Design a logging framework


Q: How would you design a logging library that supports multiple output targets (file, console,
database) with configurable formatting?

Answer approach:
• Logger class — Context that uses a Strategy for output target
• LogHandler interface — Chain of Responsibility (pass to next if level matches)
• Formatter interface — Strategy for log format (JSON, plain text, XML)
• Logger itself — Singleton pattern for global access
• Appenders wrapping each other — Decorator for adding context

💳 Scenario 2: Payment processing system


Q: Design a payment system that supports multiple payment gateways and should be easy to add
new ones.

Answer approach:
• PaymentProcessor interface — Strategy pattern for each gateway
• PaymentProcessorFactory — Factory pattern to select right processor
• PaymentFacade — Facade to simplify the orchestration
• @EventPublisher — Observer to notify on payment completion
• Builder for PaymentRequest — complex object with many optional fields
• Repository for Payment entity — abstract the persistence

⏱️ Scenario 3: Rate Limiter


Q: How would you implement a configurable rate limiter?

Answer approach:
• RateLimiter interface — Strategy (token bucket vs leaky bucket vs sliding window)
• Proxy/Decorator around your service — intercepts calls transparently

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

• Chain of Responsibility — rate limit is one filter in a chain


• Singleton for the rate limit store (or distributed cache)

8.5 Quick-Reference Cheat Sheet

Pattern Category One-liner Spring Example Interview


Hot?
Singleton Creational One instance, global @Bean default scope 🔥🔥🔥
access
Factory Creational Create without specifying BeanFactory, 🔥🔥🔥
class @Configuration
Builder Creational Build complex objects @Builder (Lombok), 🔥🔥🔥
step-by-step Request objs
Prototype Creational Clone existing objects @Scope('prototype') 🔥
beans
Adapter Structural Convert incompatible HandlerAdapter, 🔥🔥
interface RowMapper
Decorator Structural Add behavior Java I/O, @Cacheable 🔥🔥🔥
dynamically
Facade Structural Simplify complex JdbcTemplate, 🔥🔥
subsystem RestTemplate
Proxy Structural Control/intercept access @Transactional, Spring 🔥🔥🔥
AOP
Strategy Behavioral Swap algorithms at AuthenticationProvider, 🔥🔥🔥
runtime Sort
Observer Behavioral Notify dependents on ApplicationEventPublisher 🔥🔥🔥
state change
Command Behavioral Encapsulate request as Spring Batch, 🔥🔥
an object TaskExecutor
Template Behavioral Algorithm skeleton, fill in JdbcTemplate, 🔥🔥
Method steps AbstractService
Chain of Resp. Behavioral Pass request through Spring Security Filters 🔥🔥
handler chain
State Behavioral Change behavior based Order/workflow state 🔥🔥
on state machines

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Chapter 9: Your Learning Roadmap

9.1 Structured Study Plan


Week Focus Patterns to Master Practice Task
1 Creational Singleton (all variants), Factory, Build a configurable HTTP client
Builder using Builder; use Factory for
connection type selection
2 Structural Adapter, Decorator, Facade, Wrap a third-party payment SDK
Proxy with an Adapter; add logging
Decorator; create Facade for
checkout
3 Behavioral Strategy, Observer, Template Implement a sorting/filtering
Method system with Strategy; use
Observer for domain events
4 Behavioral Command, Chain of Resp., Build a request middleware
State pipeline; add undo functionality
with Command
5 Architecture Repository, MVC, DI patterns Build a complete Spring Boot
REST API applying patterns
throughout all layers
6 Interview Prep All patterns — recognition and Do mock interviews; design a
explanation system (e.g., parking lot, ride-
sharing) using patterns

9.2 Recommended Resources


• Books: 'Design Patterns' — Gang of Four (GoF), 'Head First Design Patterns' — Freeman &
Robson (more approachable)
• Books: 'Effective Java' — Joshua Bloch (best Java-specific patterns and best practices)
• Books: 'Clean Code' and 'Clean Architecture' — Robert C. Martin
• Online: [Link] — excellent visual explanations of every pattern
• Practice: [Link]/explore/learn/card/design-patterns — coding exercises
• Spring: [Link]/guides — official guides showing patterns in production Spring context

9.3 Final Advice

🎯 Remember: Patterns are Communication Tools


Design patterns are primarily a shared vocabulary. When you say 'let's use Strategy here',
your team immediately understands the structure without you drawing a diagram.

Don't force patterns. A simple if-else is often clearer than a Strategy with 3 classes.

Design Patterns Guide | Java Backend Edition


Design Patterns for Java Backend Developers | Zero to Pro + Interview Ready

Apply patterns when the problem genuinely needs it — not to show off.

In interviews: always explain WHY you'd use a pattern, not just WHAT the pattern is.
The best answer is 'I'd use [Pattern] because [specific problem it solves in this context].
The trade-off is [complexity], which is worth it because [business reason].'

Design Patterns Guide | Java Backend Edition

You might also like