Design Patterns Interview Questions and Answers (2026)
Design pattern interview questions are less about reciting the Gang of Four catalog and more about knowing when a pattern actually earns its keep versus when it's unnecessary indirection. Here are the ones that come up most often.
-
What's the difference between creational, structural, and behavioral design patterns?
Creational patterns deal with object creation, hiding the instantiation logic so the system doesn't depend on concrete classes (Singleton, Factory Method, Abstract Factory, Builder, Prototype). Structural patterns deal with how classes and objects are composed into larger structures without making the whole system fragile (Adapter, Decorator, Facade, Composite, Proxy). Behavioral patterns deal with how objects communicate and distribute responsibility at runtime (Strategy, Observer, Command, State, Template Method). In practice, this taxonomy is a useful mental checklist during design: "Is my problem about *how something gets built*, *how pieces fit together*, or *how objects talk to each other*?" That question alone often narrows you to the right pattern family before you even pick a specific pattern.
-
What is the Singleton pattern, and why is it controversial?
Singleton restricts a class to one instance and provides a global access point, typically via a private constructor and a static accessor:
public sealed class ConfigManager { private static readonly Lazy<ConfigManager> _instance = new(() => new ConfigManager()); public static ConfigManager Instance => _instance.Value; private ConfigManager() { } }It's controversial because it's effectively global mutable state: it hides dependencies (a method secretly reaching into
ConfigManager.Instanceisn't visible in its signature), makes unit testing hard (you can't easily swap in a fake), and creates hidden coupling across the app. Most modern codebases replace it with a DI container registering a service as a singleton *lifetime*, giving you the same "one instance" guarantee without the static global-state problems, and while keeping it swappable and mockable in tests. -
What's the difference between Factory Method and Abstract Factory?
Factory Method defines a single method, usually overridden in a subclass, that creates one type of product:
Shape CreateShape(). It's about deferring instantiation of *one* object to subclasses. Abstract Factory is a higher-level pattern: an interface with multiple creation methods that produces a *family* of related objects guaranteed to work together, e.g.IUIFactorywithCreateButton()andCreateCheckbox(), implemented byWindowsUIFactoryandMacUIFactoryso you never accidentally mix a Windows button with a Mac checkbox. Use Factory Method when you have one product hierarchy and want subclasses to choose the variant; use Abstract Factory when you have several related product hierarchies that must stay consistent with each other, like theming a UI toolkit or switching database providers. -
What is the Builder pattern and when do you reach for it?
Builder separates the construction of a complex object from its representation, letting you assemble it step by step instead of using a constructor with ten optional parameters:
var pizza = new PizzaBuilder() .WithSize(Size.Large) .AddTopping("Pepperoni") .AddTopping("Mushroom") .Build();It's the right call when an object has many optional fields, when construction involves multiple steps or validation that shouldn't run mid-way, or when you want immutable objects without a "telescoping constructor" problem. It also shines when the same construction process needs to produce different representations (a
StringBuilder-style API, or building both a SQL query and its parameter list from the same fluent calls). It's overkill for a class with two or three straightforward fields — that's just a constructor. -
What is the Strategy pattern and why is it one of the most useful patterns in practice?
Strategy encapsulates a family of interchangeable algorithms behind a common interface so the algorithm can vary independently of the client that uses it:
interface IShippingStrategy { decimal Calculate(Order o); } class ExpressShipping : IShippingStrategy { ... } class StandardShipping : IShippingStrategy { ... } class Checkout { private readonly IShippingStrategy _strategy; public Checkout(IShippingStrategy strategy) => _strategy = strategy; public decimal GetShippingCost(Order o) => _strategy.Calculate(o); }It's the go-to fix for long if/else or switch chains that select behavior based on a type or flag. It's popular precisely because it directly satisfies the Open/Closed Principle — adding a new shipping method means adding a new class, not editing existing logic — and because it makes each algorithm trivially unit-testable in isolation.
-
What is the Observer pattern and where does it show up in real systems?
Observer defines a one-to-many dependency where a subject notifies a list of registered observers automatically whenever its state changes, without the subject knowing concrete observer types. Classic example: a
Stockobject notifying multiplePriceDisplaywidgets when its price changes, via aSubscribe/Notifymechanism. It's everywhere in real systems: UI event handlers (buttonClickevents), pub/sub messaging systems, reactive frameworks (RxJS/Rx.NET observables), and .NET's ownevent/INotifyPropertyChangedare Observer under the hood. The benefit is loose coupling — the subject doesn't need compile-time knowledge of who's listening. The risk is memory leaks from observers that never unsubscribe, and difficulty reasoning about ordering/side effects when many observers react to the same event. -
What is the Decorator pattern and how does it differ from just subclassing?
Decorator attaches new behavior to an object dynamically by wrapping it in another object that implements the same interface, rather than creating a new subclass for every combination of features:
Stream s = new BufferedStream(new GZipStream(new FileStream(path, FileMode.Open)));Each wrapper adds one responsibility (buffering, compression) while conforming to the same
Streamcontract. The advantage over subclassing is combinatorial: with inheritance, supporting "buffered + compressed + encrypted" file streams would require a new subclass per combination; decorators let you compose any subset at runtime by nesting wrappers. It's the right pattern when responsibilities need to be added/removed independently and combined flexibly — coffee order add-ons and ASP.NET Core middleware pipelines are both textbook Decorator use cases. -
What is the Adapter pattern and when would you use it over changing the underlying code?
Adapter converts the interface of an existing class into another interface that client code expects, letting incompatible types work together without modifying either side:
interface ITemperatureSensor { double GetCelsius(); } class LegacyFahrenheitSensor { public double GetFahrenheit() => 98.6; } class SensorAdapter : ITemperatureSensor { private readonly LegacyFahrenheitSensor _legacy; public double GetCelsius() => (_legacy.GetFahrenheit() - 32) * 5.0 / 9.0; }You reach for Adapter specifically when you can't or shouldn't modify the original class — it's a third-party library, a legacy component you don't own, or changing it would ripple through other consumers. It's a thin, deliberately dumb translation layer; if you find yourself adding real logic inside the adapter, that's a sign the abstraction boundary is in the wrong place.
-
What is the Facade pattern and how is it different from Adapter?
Facade provides a single simplified interface over a complex subsystem of multiple classes, hiding their interactions from the caller. For example, an
OrderService.PlaceOrder()facade might internally coordinate inventory checks, payment processing, and shipping — the caller sees one method call instead of orchestrating five subsystems itself. The key difference from Adapter: Adapter's job is *compatibility* — making an existing interface look like a different expected interface, usually wrapping one class. Facade's job is *simplification* — reducing the surface area of many classes into one convenient entry point; it doesn't need to match any existing interface at all. Facade is one of the most underused-in-name-but-overused-in-practice patterns — most "service" classes in layered architectures are Facades over lower-level components. -
What is the Repository pattern and what problem does it actually solve?
Repository mediates between the domain/business logic and data access code, exposing a collection-like interface (
GetById,Add,Find) that hides whether data comes from SQL, an ORM, a cache, or an API:interface IOrderRepository { Order GetById(int id); void Add(Order order); IEnumerable<Order> FindByCustomer(int customerId); }The real value isn't "abstracting the database" in the abstract — it's decoupling business logic from persistence details so you can unit test services against an in-memory fake repository instead of hitting a real database, and so you can swap persistence technology without touching business rules. The common critique is that it can become a redundant wrapper around an ORM that already provides this abstraction (e.g., EF Core's
DbSetis already a repository); it earns its keep when you need to hide genuinely complex queries or support multiple data sources. -
How is Dependency Injection itself a design pattern, and how does it relate to Inversion of Control?
DI is the pattern of supplying an object's dependencies from the outside (via constructor, property, or method) rather than having the object construct them itself:
class OrderService { private readonly IPaymentGateway _gateway; public OrderService(IPaymentGateway gateway) => _gateway = gateway; // injected, not `new`ed }It's a specific technique for achieving Inversion of Control — the broader principle that a framework or container, not your code, decides when and what to instantiate. DI is what makes Strategy, Repository, and most testable architectures actually work in practice: you inject the interface, and a DI container (or manual composition root) wires up the concrete implementation at startup. The payoff is that
OrderServicecan be unit tested with a mockIPaymentGatewaywithout ever touching a real payment processor. -
When should you *not* use a design pattern?
When it adds indirection without solving a real, present problem. A classic mistake is introducing a Strategy pattern with an interface and three classes for logic that will only ever have one implementation, or wrapping a two-property DTO in a Builder. Patterns exist to manage change and complexity — if there's no variability to abstract over and no evidence more will appear, you're paying the cost (extra files, extra indirection, harder-to-follow call stacks) for a benefit that never materializes. A good heuristic: don't introduce an abstraction until you have at least two concrete cases that need it, or a specific, near-term reason to expect a second one. "We might need it later" is usually not that reason — YAGNI (You Aren't Gonna Need It) is as important an engineering principle as any pattern itself.
Practicing for a real interview? Get live AI help with your answers, in the browser, free to start.
Start a free session