A comprehensive guide to ace design pattern interview questions with confidence.
- Most Frequently Asked Patterns
- Pattern Comparison Chart
- Common Interview Questions
- Pattern Selection Guide
- Red Flags to Avoid
- Interview Tips
-
Singleton Pattern ⭐⭐⭐⭐⭐
- Almost guaranteed to be asked
- Focus on: Thread safety, lazy initialization, alternatives
- Common question: "How do you prevent multiple instances?"
-
Factory Pattern ⭐⭐⭐⭐⭐
- Very common, especially for backend roles
- Focus on: When to use vs constructors, extensibility
- Common question: "Difference between Factory and Abstract Factory?"
-
Observer Pattern ⭐⭐⭐⭐
- Common for frontend/full-stack roles
- Focus on: Pub-sub systems, event handlers
- Common question: "How would you implement a notification system?"
-
Strategy Pattern ⭐⭐⭐⭐
- Popular for algorithm-heavy roles
- Focus on: Runtime behavior change, avoiding conditionals
- Common question: "Difference between Strategy and State?"
-
Decorator Pattern ⭐⭐⭐⭐
- Common across all roles
- Focus on: Adding functionality dynamically
- Common question: "How is this different from inheritance?"
- Adapter Pattern ⭐⭐⭐
- Facade Pattern ⭐⭐⭐
- Builder Pattern ⭐⭐⭐
- Command Pattern ⭐⭐⭐
- Proxy Pattern ⭐⭐⭐
| Pattern | Type | Problem It Solves | When NOT to Use | Similar To |
|---|---|---|---|---|
| Singleton | Creational | Need exactly one instance | Multiple instances are fine | None |
| Factory | Creational | Complex object creation | Simple constructors suffice | Abstract Factory |
| Abstract Factory | Creational | Create families of related objects | Only one product type | Factory Method |
| Builder | Creational | Complex object with many parameters | Simple objects | Factory |
| Prototype | Creational | Clone expensive objects | Creation is cheap | None |
| Adapter | Structural | Make incompatible interfaces work | Interfaces already compatible | Bridge |
| Decorator | Structural | Add functionality dynamically | Static behavior is fine | Proxy |
| Facade | Structural | Simplify complex subsystem | System is already simple | Adapter |
| Proxy | Structural | Control access to object | No access control needed | Decorator |
| Strategy | Behavioral | Multiple algorithms for same task | Only one algorithm | State |
| Observer | Behavioral | One-to-many notifications | No event system needed | Mediator |
| Command | Behavioral | Parameterize and queue operations | Direct method calls work | Strategy |
| State | Behavioral | Behavior changes with state | State doesn't affect behavior | Strategy |
| Template Method | Behavioral | Algorithm skeleton with variations | Algorithm doesn't vary | Strategy |
Good Answer Structure:
- Situation: Describe the problem
- Pattern Choice: Explain why you chose this pattern
- Implementation: Brief technical details
- Result: What improved (maintainability, performance, etc.)
Example:
"In our e-commerce platform, we had 10+ payment methods with complex initialization logic scattered across controllers. I implemented the Factory Pattern to centralize payment gateway creation. This reduced code duplication by 60% and made adding new payment methods trivial—just register a new factory method. When Stripe added Buy Now Pay Later, we integrated it in 30 minutes without touching existing code."
Answer:
- Strategy: Client chooses which strategy to use; strategies are independent
- Focus: HOW to do something (algorithms)
- Example: Payment methods (credit card, PayPal, crypto)
- State: Context automatically changes state; states are interdependent
- Focus: WHAT state we're in (behavior)
- Example: Order states (pending → paid → shipped)
Key Insight: "Strategy is about swapping algorithms; State is about swapping behavior based on internal state."
Answer: Avoid Singleton when:
- Testing is important (hard to mock singletons)
- You need different instances for different contexts
- The "single instance" requirement might change
- You're using dependency injection (DI container manages lifecycle)
- Global state creates hidden dependencies
Better alternatives:
- Dependency Injection
- Monostate Pattern
- Session Scopes
TypeScript Answer:
class Singleton {
private static instance?: Singleton;
private static creating = false;
private constructor() {
if (Singleton.creating) {
throw new Error("Use Singleton.getInstance()");
}
}
static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.creating = true;
Singleton.instance = new Singleton();
Singleton.creating = false;
}
return Singleton.instance;
}
}Note: JavaScript/TypeScript is single-threaded, but mention:
- Double-checked locking (Java/C++)
- Initialization-on-demand holder idiom
- Enum singletons (Java)
Answer:
Factory Method (One product type):
interface Button {
render(): void;
}
class WindowsButton implements Button {
render() {
/* Windows style */
}
}
class MacButton implements Button {
render() {
/* Mac style */
}
}
class ButtonFactory {
static create(os: string): Button {
return os === "windows" ? new WindowsButton() : new MacButton();
}
}Abstract Factory (Family of products):
interface UIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class WindowsFactory implements UIFactory {
createButton() {
return new WindowsButton();
}
createCheckbox() {
return new WindowsCheckbox();
}
}
class MacFactory implements UIFactory {
createButton() {
return new MacButton();
}
createCheckbox() {
return new MacCheckbox();
}
}Key Difference: "Factory creates one type; Abstract Factory creates related families."
Answer: Command Pattern
interface Command {
execute(): void;
undo(): void;
}
class AddTextCommand implements Command {
constructor(private editor: Editor, private text: string) {}
execute() {
this.editor.addText(this.text);
}
undo() {
this.editor.removeText(this.text);
}
}
class CommandHistory {
private history: Command[] = [];
private current = -1;
execute(cmd: Command) {
cmd.execute();
this.history = this.history.slice(0, this.current + 1);
this.history.push(cmd);
this.current++;
}
undo() {
if (this.current >= 0) {
this.history[this.current--].undo();
}
}
redo() {
if (this.current < this.history.length - 1) {
this.history[++this.current].execute();
}
}
}// Interviewer shows this code
class Singleton {
static instance = new Singleton();
constructor() {}
}Answer: Issues:
- ❌ Constructor is public (can create multiple instances)
- ❌ Eager initialization (created whether needed or not)
- ❌ Can't control initialization timing
- ❌ Can't pass parameters to constructor
- ❌ No lazy loading
Better:
class Singleton {
private static instance?: Singleton;
private constructor() {} // Private!
static getInstance(): Singleton {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
}Answer: Yes, for many patterns!
Strategy with functions:
// Instead of Strategy classes
type SortStrategy = (arr: number[]) => number[];
const quickSort: SortStrategy = (arr) => {
/* ... */
};
const mergeSort: SortStrategy = (arr) => {
/* ... */
};
function sort(arr: number[], strategy: SortStrategy) {
return strategy(arr);
}Observer with callbacks:
type Callback = (data: any) => void;
class EventEmitter {
private listeners: Callback[] = [];
on(callback: Callback) {
this.listeners.push(callback);
}
emit(data: any) {
this.listeners.forEach((cb) => cb(data));
}
}When OOP patterns are better:
- Strategies have state
- Multiple related methods
- Need inheritance/polymorphism
- Team prefers OOP
Need to create objects?
├─ YES → Creational Patterns
│ ├─ Only one instance needed? → Singleton
│ ├─ Complex creation logic? → Factory/Builder
│ ├─ Create families of objects? → Abstract Factory
│ └─ Clone expensive objects? → Prototype
│
├─ Need to compose objects/classes?
│ → Structural Patterns
│ ├─ Incompatible interfaces? → Adapter
│ ├─ Add functionality dynamically? → Decorator
│ ├─ Simplify complex system? → Facade
│ └─ Control access? → Proxy
│
└─ Need to define object interactions?
→ Behavioral Patterns
├─ Multiple algorithms? → Strategy
├─ Notify multiple objects? → Observer
├─ Behavior changes with state? → State
├─ Parameterize operations? → Command
└─ Define algorithm steps? → Template Method
| Use Case | Recommended Pattern |
|---|---|
| Payment methods | Strategy |
| Logging system | Singleton + Strategy |
| UI component library | Factory + Decorator |
| Event system | Observer |
| API client | Singleton + Facade |
| Database connections | Factory + Proxy |
| Undo/Redo | Command |
| Form validation | Strategy + Chain of Responsibility |
| Authentication | Strategy + Decorator |
| Caching | Proxy |
- "I use Singleton for everything"
- Shows lack of understanding
- Singletons are often overused
- "I memorized all 23 patterns"
- Interviewer wants practical knowledge
- Focus on 5-10 most common
- "Design patterns solve all problems"
- Sometimes simple code is better
- Don't over-engineer
- Can't explain WHEN NOT to use a pattern
- As important as knowing when to use it
- Confusing similar patterns
- Strategy vs State
- Factory vs Abstract Factory
- Adapter vs Facade
- Decorator vs Proxy
- "I chose X over Y because..."
- Shows critical thinking
- "Here's a time I refactored to a pattern"
- Real-world experience
- "This pattern has trade-offs..."
- Understanding limitations
- "In JavaScript/TypeScript, I might use..."
- Language-specific knowledge
- "I'd avoid this pattern here because..."
- Knowing when NOT to use patterns
- Practice top 5 patterns - Implement from scratch
- Know real-world examples - From your projects
- Understand trade-offs - Every pattern has drawbacks
- Study pattern relationships - How they differ and relate
- Review your resume - Be ready to discuss patterns you've used
-
Ask clarifying questions
- "What scale are we talking about?"
- "Are there performance constraints?"
- "Will this need to be extended?"
-
Think aloud
- Explain your reasoning
- Discuss alternatives
- Mention trade-offs
-
Start simple
- Begin with straightforward solution
- Then discuss patterns for improvement
- Don't over-engineer immediately
-
Draw diagrams
- UML helps communicate
- Show relationships
- Visualize flow
-
Discuss testing
- How pattern affects testability
- Mocking strategies
- Test examples
Interviewer: "Design a notification system that can send emails, SMS, and push notifications."
Good Response:
-
Clarify (2 minutes)
- "How many notification types? Will more be added?"
- "Do we need delivery tracking?"
- "Any priority or batching requirements?"
-
Start Simple (3 minutes)
- "I'll start with a simple interface..."
interface NotificationService { send(recipient: string, message: string): Promise<void>; }
-
Introduce Pattern (5 minutes)
- "As we add notification types, I'd use the Factory Pattern to handle creation..."
- Show implementation
- "We could also use Strategy if we need runtime switching..."
-
Discuss Extensions (3 minutes)
- "For retry logic, I'd add Decorator Pattern..."
- "For delivery tracking, Observer Pattern..."
-
Address Concerns (2 minutes)
- "Trade-off: More classes but easier to extend"
- "Testing: Can mock each service independently"
- Singleton: One instance only
- Factory Method: Create objects via factory
- Abstract Factory: Create families of objects
- Builder: Construct complex objects step-by-step
- Prototype: Clone objects
- Adapter: Make interfaces compatible
- Bridge: Separate abstraction from implementation
- Composite: Tree structure of objects
- Decorator: Add functionality dynamically
- Facade: Simplified interface
- Flyweight: Share common data
- Proxy: Control access
- Chain of Responsibility: Pass request along chain
- Command: Encapsulate requests
- Iterator: Traverse collections
- Mediator: Centralize communication
- Memento: Save/restore state
- Observer: Subscribe to events
- State: Change behavior with state
- Strategy: Encapsulate algorithms
- Template Method: Define algorithm skeleton
- Visitor: Add operations to objects
Before your interview, make sure you can:
- Implement top 5 patterns from scratch
- Explain when NOT to use each pattern
- Give 2-3 real-world examples per pattern
- Compare similar patterns (Strategy vs State, etc.)
- Discuss trade-offs and alternatives
- Draw UML diagrams for key patterns
- Explain thread-safety (for Singleton)
- Discuss testing strategies with patterns
- Show TypeScript-specific implementations
- Mention design principles (SOLID)
- Implement patterns in this repository
- Solve LeetCode design problems
- Review open-source projects using patterns
- "Design Patterns" - Gang of Four (Original)
- "Head First Design Patterns" (Beginner-friendly)
- Refactoring.Guru (Great visualizations)
- Complete all patterns in this repo
- Build a real project using 3-5 patterns
- Practice explaining patterns to others
- Mock interview with peers
Remember:
- Understanding > Memorization
- Practical > Theoretical
- Simple > Complex
- Communication > Perfect Code
You've got this! 💪