In short
A design pattern is a named, reusable solution to a problem that recurs in object-oriented design - not code to copy, but a structure of classes and objects plus the trade-offs it brings. The standard catalogue is the 23 "Gang of Four" (GoF) patterns of Gamma, Helm, Johnson and Vlissides (1994), grouped as creational, structural and behavioural. Patterns are examined in university Software Engineering and Object-Oriented Analysis and Design papers (AICTE model curriculum / CBCS), in UGC-NET Computer Science, ISRO and NIELIT papers; current GATE CSE syllabus does not carry software engineering, so treat it as a placement and university topic. In interviews they are near-certain: Indian service companies (TCS, Infosys, Wipro, Cognizant, Accenture, Capgemini) ask them around Java/Spring, and product companies (Flipkart, Zomato, Swiggy, Razorpay, PhonePe, Zoho, Freshworks) ask you to name and apply them in a design round.
Explained
What a pattern is, and the vocabulary
- Definition (Christopher Alexander, adapted by GoF): a pattern describes a problem that occurs over and over, the core of its solution, and the consequences - so the solution can be reused without reinventing it.
- Four essential elements: (1) pattern name, (2) problem / when to apply, (3) solution - the participating classes, their roles and collaborations, (4) consequences - benefits and costs.
- Classification by purpose: creational (how objects are created - 5), structural (how classes and objects are composed - 7), behavioural (how objects distribute responsibility and communicate - 11). Total 23.
- Classification by scope: class patterns use inheritance, fixed at compile time (Factory Method, class Adapter, Template Method, Interpreter); object patterns use composition and delegation, changeable at run time (all the rest).
- Levels above and below patterns: *idioms* (language-specific, e.g. Java's
equals/hashCodecontract) < *design patterns* < *architectural styles* (layered, microservices, event-driven). - A pattern is not a framework, not a library, not an algorithm, and not a data structure.
Principles that generate the patterns
- Program to an interface, not an implementation - clients depend on the abstract type, so implementations can be swapped.
- Favour object composition over class inheritance - inheritance is white-box reuse fixed at compile time; composition is black-box and run-time changeable (Strategy, Decorator, Bridge all follow this).
- Encapsulate what varies - isolate the changing part behind an interface; the rest of the code stops changing.
- SOLID: Single responsibility, Open-closed (open to extension, closed to modification), Liskov substitution, Interface segregation, Dependency inversion (depend on abstractions).
- Hollywood principle / Inversion of Control - "don't call us, we'll call you": the framework calls your hook method (Template Method, Spring's bean container).
- Law of Demeter (talk only to immediate friends) reduces coupling - Facade and Mediator are its practical form.
Creational patterns (5)
- Singleton: ensure a class has exactly one instance and give a global access point. Use for a configuration holder, logger, connection-pool manager. Implement with a private constructor + static accessor; thread-safe forms are eager static field,
enum, Bill Pugh static holder, or double-checked locking withvolatile. - Factory Method: define an interface for creating an object but let subclasses decide which class to instantiate - "virtual constructor". Creation is deferred to a subclass hook; e.g.
Collection.iterator(), where each collection returns its ownIterator, or aDocumentCreatorsubclassed per document type. (A staticgetInstance()helper is the Simple/Static Factory idiom, not this pattern.) - Abstract Factory: an interface for creating families of related products without naming concrete classes - e.g. one UI factory producing Android widgets, another producing iOS widgets, so the family is never mixed.
- Builder: separate the construction of a complex object from its representation, so the same process builds different results. Used for objects with many optional fields (a fluent
Pizza.Builder().cheese().jain().build()); avoids a telescoping constructor and gives immutable objects. - Prototype: create new objects by cloning an existing instance instead of calling a constructor - useful when creation is costly or the exact class is decided at run time. Needs care over shallow vs deep copy (Java
Cloneable/clone()is shallow by default). - Related non-GoF: Object Pool (reuse expensive objects - JDBC connection pools, thread pools) and Dependency Injection (an external container supplies collaborators - Spring, Guice).
Structural patterns (7)
- Adapter (wrapper): convert an existing interface into the one a client expects - e.g. wrapping a legacy bank XML gateway behind your
PaymentGatewayinterface. Class adapter uses inheritance, object adapter uses composition. - Bridge: decouple an abstraction from its implementation so both can vary independently - two parallel hierarchies joined by composition; prevents a class explosion.
- Composite: treat individual objects and compositions of objects uniformly through one component interface - file/folder trees, UI containers, nested order items, organisation hierarchies.
- Decorator: attach extra responsibilities to an object dynamically by wrapping it in an object with the same interface - Java I/O (
new BufferedReader(new FileReader(f))), add-ons priced on a base product. - Facade: a single simplified interface to a complicated subsystem - one
BookingFacadehiding seat inventory, pricing, payment and SMS services. Reduces client coupling, does not forbid direct access. - Flyweight: share fine-grained objects to save memory by splitting intrinsic (shared, immutable) state from extrinsic (passed in) state - map markers, characters in an editor, Java's
Integer.valueOfcache (−128..127), interned strings. - Proxy: a surrogate controlling access to another object - virtual proxy (lazy loading, Hibernate's lazy entities), remote proxy (RMI stub), protection proxy (access checks), smart reference; Spring AOP proxies add transactions and logging.
Behavioural patterns (11)
- Observer (publish-subscribe): when one object changes state, all registered dependents are notified automatically - UI event listeners, stock tickers,
java.util.Observer(deprecated), RxJava, Spring events. - Strategy: define a family of interchangeable algorithms, encapsulate each, and select one at run time - sorting comparators, surge-pricing rules, UPI/card/wallet payment handlers. Replaces long
if-else/switchchains on type. - State: let an object alter its behaviour when its internal state changes, by delegating to a state object - an order moving through Placed → Packed → Shipped → Delivered. Structurally identical to Strategy; the difference is intent (states know and trigger transitions; strategies are chosen by the client).
- Template Method: define a skeleton algorithm in a base class with abstract hook steps overridden by subclasses -
AbstractReportGenerator.generate()callingfetch(),format(),export(); JUnit's setUp/tearDown. - Command: encapsulate a request as an object, so it can be queued, logged, parameterised and undone - menu actions, undo/redo stacks, job queues,
Runnable. - Chain of Responsibility: pass a request along a chain of handlers until one handles it - servlet filters, Spring Security filter chain, leave-approval or expense-approval escalation.
- Iterator: access elements of an aggregate sequentially without exposing its representation -
Iterator/Iterable,for-each. - Mediator: centralise complex many-to-many communication in one mediator object so components refer only to it - air-traffic-control analogy, chat room, a form whose fields enable/disable each other.
- Memento: capture and restore an object's internal state without violating encapsulation - editor undo snapshot, game save, database savepoint analogy.
- Visitor: add new operations to a stable object structure without changing its classes, using double dispatch - AST traversal in compilers, tax/report calculations over a node tree.
- Interpreter: represent a grammar as a class hierarchy and interpret sentences in it - regular expressions, rule engines, simple query/formula evaluators.
Patterns in frameworks, and compound patterns
- MVC is a compound pattern: Observer (view updates on model change) + Strategy (controller is the view's strategy) + Composite (nested views). Variants: MVP, MVVM (Android Jetpack, WPF), MVC in Spring MVC, Laravel, Django (MTV naming).
- Spring Framework examples:
BeanFactory/ApplicationContext(Factory + Singleton-scoped beans),JdbcTemplate/RestTemplate(Template Method), AOP (Proxy + Decorator),@Transactional(Proxy), event listeners (Observer),RowMapper(Strategy). - Java library examples:
java.iostreams (Decorator),Arrays.asList(Adapter),Collections.unmodifiableList(Proxy/Decorator),StringBuilder(Builder),Runtime.getRuntime()(Singleton),Thread/Runnable(Command, Strategy). - Enterprise / data patterns commonly asked in Indian service-industry interviews: DAO, Repository, Service Layer, DTO / Value Object, Front Controller (
DispatcherServlet), Business Delegate, Unit of Work, Active Record (Rails, Django ORM). - Concurrency-related: thread pool, producer-consumer, double-checked locking, immutable object, read-write lock, future/promise.
- Anti-patterns: God object / blob, spaghetti code, Golden hammer (one pattern for everything), Singletonitis (global mutable state, untestable), anemic domain model, poltergeist, yo-yo problem (deep inheritance), circular dependency, premature "patternitis" where a simple function would do.
- Criticism to be aware of: many GoF patterns compensate for missing language features - first-class functions make Strategy and Command a lambda; Python's modules make Singleton unnecessary; this is a fair interview answer, not a reason to be ignorant of the catalogue.
Key points
- Design pattern - a named, documented, reusable solution plus its consequences, at the class/object level.
- GoF count - 23 patterns: 5 creational, 7 structural, 11 behavioural.
- Scope - class patterns use inheritance (compile-time); object patterns use composition (run-time).
- Singleton - one instance, global access; prefer
enumor static holder; dangerous as hidden global state. - Factory Method vs Abstract Factory - one product via a subclass hook vs a whole family via a factory object.
- Builder - step-by-step construction of complex/immutable objects with many optional parameters.
- Prototype - clone rather than construct; mind deep vs shallow copy.
- Adapter vs Facade - adapter changes an interface to a required one; facade simplifies many interfaces into one.
- Decorator vs Proxy - both wrap with the same interface; decorator adds behaviour, proxy controls access.
- Bridge - two independent hierarchies (abstraction and implementation) joined by composition, avoiding m × n classes.
- Composite - uniform treatment of leaf and container through one interface; recursive structure.
- Flyweight - share intrinsic state, pass extrinsic state, to cut memory for huge object counts.
- Observer - one-to-many automatic notification; the basis of event-driven UIs and pub-sub.
- Strategy - interchangeable algorithms chosen at run time; kills type-based
switchchains. - State vs Strategy - same structure, different intent: state transitions internally, strategy is set by the client.
- Template Method - fixed algorithm skeleton, variable steps; Hollywood principle / IoC.
- Chain of Responsibility vs Command - a request passed down handlers vs a request stored as an object for later/undo.
- Open-closed principle - most patterns exist to let you extend behaviour by adding classes, not editing existing ones.
Examples
1. Thread-safe Singleton - three correct forms, one wrong one
// (a) WRONG under concurrency: two threads can both see instance == null
static Logger get(){ if (inst == null) inst = new Logger(); return inst; }
// (b) Double-checked locking - volatile is mandatory
class Logger {
private static volatile Logger inst;
private Logger(){}
static Logger get(){
if (inst == null) { // 1st check, no lock
synchronized (Logger.class) {
if (inst == null) inst = new Logger();// 2nd check, under lock
}
} return inst;
}
}
// (c) Bill Pugh holder - lazy, no locking
class Cfg { private Cfg(){}
private static class H { static final Cfg I = new Cfg(); }
static Cfg get(){ return H.I; } }
// (d) enum singleton - serialization- and reflection-safe
enum Registry { INSTANCE; private final Map<String,String> m = new HashMap<>(); }
Note: Spring's default singleton bean scope means one instance per application context, not one per JVM - a standard interview trap.
2. Strategy removes a conditional - count the change A payment service supports UPI, card, net-banking and wallet, each with 3 variants: an if-else on 4 × 3 = 12 combinations sits in one method that must be edited for every new mode. With Strategy you add 1 class per mode and the service never changes.
interface Payment { long charge(long paise); } // amounts in paise
class Upi implements Payment { public long charge(long p){ return p; } } // 0% MDR
class Card implements Payment { public long charge(long p){ return p + p*2/100; } } // 2%
class Checkout { private final Payment p; Checkout(Payment p){ this.p = p; }
long pay(long amt){ return p.charge(amt); } }
For ₹2,000 (200000 paise): UPI → ₹2,000.00; Card → 200000 + 4000 = 204000 paise = ₹2,040.00.
3. Decorator - priced add-ons on a base product Base Masala Chai ₹25; decorators: extra milk ₹10, ginger ₹5, large ₹15. new Large(new Ginger(new ExtraMilk(new MasalaChai()))) → cost = 25 + 10 + 5 + 15 = ₹55. With subclassing you would need one class per combination: 3 independent add-ons → 2³ = 8 subclasses; with Decorator, 1 base + 3 decorators = 4 classes, and any of the 8 combinations is built at run time.
4. Bridge - avoiding the class explosion Shapes {Circle, Square, Triangle} to be drawn by renderers {SVG, Canvas, PDF, Printer}.
- Pure inheritance: 3 × 4 = 12 concrete classes; adding a 4th shape → 16.
- Bridge:
Shapeholds aRenderer; 3 shape classes + 4 renderer classes = 7 concrete classes (+2 abstractions); adding a shape costs 1 class, adding a renderer costs 1.
| Classes needed | Inheritance (m × n) | Bridge (m + n) |
|---|---|---|
| 3 shapes × 4 renderers | 12 | 7 |
| 5 shapes × 6 renderers | 30 | 11 |
5. Flyweight - memory saved on a map view A metro-map screen shows 2,00,000 station/stop markers. Each marker object = 64 bytes of intrinsic state (icon reference, colour, label style) + 16 bytes of extrinsic state (x, y).
- Without Flyweight: 2,00,000 × 80 B = 1,60,00,000 B ≈ 15.26 MiB.
- With Flyweight (only 5 distinct icon types shared): 5 × 64 B + 2,00,000 × 16 B = 320 + 32,00,000 = 32,00,320 B ≈ 3.05 MiB.
- Saving = 1 − 3.2003/16.0 = 80.0% of the memory.
6. "Name the pattern" - the classic exam question
| Scenario | Pattern |
|---|---|
| Hibernate returns a stub object and hits the DB only when a getter is called | Proxy (virtual) |
BufferedInputStream wraps a FileInputStream | Decorator |
One ReportService method fixes the steps; subclasses override fetchData() | Template Method |
| A leave request escalates manager → HR → director until approved | Chain of Responsibility |
| An order object behaves differently as Placed / Shipped / Cancelled | State |
Legacy SOAP gateway used through your new PaymentGateway interface | Adapter |
| Dashboard widgets refresh when the data model updates | Observer |
Pizza.Builder().thinCrust().extraCheese().build() | Builder |
One TravelFacade.book() hides flight, hotel, payment and SMS subsystems | Facade |
Folder containing files and sub-folders, both with getSize() | Composite |
Comparison table - the four confusable pairs
| Pair | Same structure? | Difference in intent |
|---|---|---|
| Strategy vs State | Yes | Client picks the algorithm vs object changes its own state and transitions |
| Adapter vs Facade | No | Convert one interface vs simplify many |
| Decorator vs Proxy | Yes | Add responsibilities vs control/defer access |
| Factory Method vs Abstract Factory | No | Subclass hook for one product vs object creating a product family |
Where it is used
- Java/Spring enterprise development (TCS, Infosys, Wipro, HCLTech, Cognizant, LTIMindtree): DAO, Front Controller, Proxy for
@Transactional, Template Method inJdbcTemplate, DI everywhere - asked in nearly every Java interview. - Consumer product engineering (Flipkart, Swiggy, Zomato, Zepto, Ola, MakeMyTrip): Strategy for pricing/surge and payment routing, State for order lifecycle, Observer for notifications, Chain of Responsibility for request filters.
- Fintech and payments (Razorpay, PhonePe, Paytm, Pine Labs, banks' UPI stacks): Adapter per bank/PSP integration, Factory for gateway selection, Command for retried/queued transactions, Proxy for rate limiting and idempotency.
- Mobile apps (Android with Jetpack, Flutter): MVVM, Observer via LiveData/StateFlow, Builder for
NotificationCompat.Builder, Singleton for Room database instances. - Product and SaaS firms (Zoho, Freshworks, Postman, Atlassian India): plug-in architectures built on Strategy, Decorator and Visitor; multi-tenant configuration via Abstract Factory.
- Job roles: SDE-1/SDE-2 (low-level design rounds), Java/.NET developer, Android/iOS developer, framework and platform engineer, technical architect; also UGC-NET/ISRO/NIELIT and PSU IT recruitment papers.
Interview questions
- Q: What is a design pattern and what are its four elements? A: A named, reusable solution to a recurring design problem; its elements are name, problem/applicability, solution (classes and collaborations) and consequences.
- Q: How many GoF patterns are there and how are they classified? A: 23 - 5 creational, 7 structural, 11 behavioural; also split by scope into class (inheritance-based) and object (composition-based) patterns.
- Q: Give a thread-safe Singleton and explain why
volatileis needed. A: Use anenumor the static-holder idiom; in double-checked lockingvolatileprevents a thread from seeing a partially constructed object due to instruction reordering and stale caches. - Q: Why is Singleton often called an anti-pattern? A: It is global mutable state - it hides dependencies, makes unit testing and mocking hard, breaks in clustered deployments and can serialise access under load.
- Q: Difference between Factory Method and Abstract Factory? A: Factory Method is one method overridden by a subclass to create one product; Abstract Factory is an object with several such methods creating a consistent family of products.
- Q: When would you use Builder instead of a constructor? A: When an object has many optional parameters or must be immutable - it avoids telescoping constructors and makes the construction code readable and validated in one place.
- Q: Decorator vs inheritance for adding features? A: Decorator composes at run time and supports any combination of features with n classes; inheritance fixes the combination at compile time and needs up to 2ⁿ subclasses.
- Q: Strategy and State have identical class diagrams - how do they differ? A: Only in intent: in Strategy the client chooses an interchangeable algorithm and it rarely changes; in State the object switches behaviour itself as its lifecycle state changes, and states often decide the next state.
- Q: Which pattern underlies Spring's
@Transactional? A: Proxy (a JDK dynamic proxy or CGLIB subclass) created by AOP, which opens and commits the transaction around your method call. - Q: What pattern is MVC? A: A compound pattern - Observer between model and views, Strategy between view and controller, and Composite for nested views.
- Q: How do lambdas and first-class functions change pattern usage? A: Strategy, Command, Observer callbacks and Template Method hooks often collapse into a lambda or method reference, so the pattern remains but the boilerplate class disappears.
- Q: Give a case where applying a pattern is wrong. A: Wrapping a two-line calculation in Strategy + Factory + Builder - it adds indirection, classes and reading cost with no variation to absorb; patterns are justified only by actual or imminent change.
Common mistakes
- Reciting structure without intent - the diagrams of Strategy/State and Decorator/Proxy are the same; interviewers mark the *why*, not the boxes.
- Writing the naive lazy Singleton in a multithreaded question, or omitting
volatilein double-checked locking. - Confusing Adapter, Facade, Decorator and Proxy - remember: convert, simplify, add, control.
- Treating Abstract Factory and Factory Method as synonyms, or calling any static
createX()helper a GoF Factory Method (that is the Simple/Static Factory idiom). - Over-engineering (patternitis) - forcing patterns into small code, producing 10 classes where one function suffices; equally, pattern names used as decoration on code that does not follow them.
- Breaking Prototype with a shallow clone - the copy shares mutable collections with the original, causing hidden aliasing bugs.
- Forgetting the consequences section in exam answers - full marks need benefits *and* costs (extra classes, indirection, debugging difficulty), with a UML sketch and participant names.
Related topics
Low-level design (object-oriented design) interviews · Requirements engineering and UML · Software architecture: monoliths and microservices · Clean code and code reviews · Object-oriented programming concepts in Java · Test automation and TDD