A class should have only one reason to change. SRP keeps classes focused, testable, and easy to maintain.
Software entities should be open for extension but closed for modification. Add new behavior without editing existing code.
Subtypes must be substitutable for their base types without altering program correctness. Violated when a subclass weakens postconditions or strengthens preconditions.
No client should be forced to depend on methods it does not use. Prefer many small, role-specific interfaces over one fat interface.
High-level modules should not depend on low-level modules; both should depend on abstractions. The cornerstone of testable, decoupled architecture.
Favor composing objects via has-a relationships over extending via is-a. Composition gives flexibility, avoids fragile base-class problems.
Bundling data with the methods that operate on it while restricting direct access to internal state. The foundation of information hiding.
Runtime polymorphism (method overriding / dynamic dispatch) vs compile-time polymorphism (method overloading). Know when and why each is used.
When to use an abstract class (shared state + partial implementation) vs an interface (pure contract, multiple inheritance of type).
Intent: Ensure a class has exactly one instance and provide a global access point. When to use: Database connection pools, configuration managers, caches.
Intent: Separate construction of a complex object from its representation. When to use: Objects with many optional parameters, immutable objects with fluent APIs.
Intent: Define an interface for creating an object but let subclasses decide which class to instantiate. When to use: When the creation logic varies by context or configuration.
Intent: Provide an interface for creating families of related objects without specifying concrete classes. When to use: Cross-platform UI toolkits, themed component sets.
Intent: Create new objects by cloning an existing instance (prototype). When to use: When object creation is expensive and a similar object already exists.
Intent: Attach additional responsibilities to an object dynamically, providing a flexible alternative to subclassing. When to use: Wrapping I/O streams, adding logging/caching layers.
Intent: Convert the interface of a class into another interface that clients expect. When to use: Integrating legacy code, third-party libraries with incompatible interfaces.
Intent: Provide a surrogate or placeholder for another object to control access. When to use: Lazy loading, access control, logging, AOP interceptors.
Intent: Provide a unified, simplified interface to a set of interfaces in a subsystem. When to use: Hiding complex subsystem interactions behind a clean API.
Intent: Compose objects into tree structures to represent part-whole hierarchies. Clients treat individual objects and compositions uniformly. When to use: File systems, UI component trees, organizational hierarchies.
Intent: Use sharing to support large numbers of fine-grained objects efficiently. When to use: When many objects share intrinsic state and differ only in extrinsic state.
Intent: Define a family of algorithms, encapsulate each one, and make them interchangeable at runtime. When to use: Payment processing, sorting strategies, pricing rules.
Intent: Define a one-to-many dependency so that when one object changes state, all dependents are notified. When to use: Event systems, pub-sub, UI listeners.
Intent: Encapsulate a request as an object, allowing parameterization, queuing, logging, and undo/redo operations. When to use: Task queues, macro recording, transactional systems.
Intent: Pass a request along a chain of handlers until one handles it. Decouples sender from receiver. When to use: Servlet filters, logging frameworks, approval workflows.
Intent: Allow an object to alter its behavior when its internal state changes. The object appears to change its class. When to use: Order lifecycle, vending machines, document workflows.
Intent: Define the skeleton of an algorithm in a superclass, letting subclasses override specific steps. When to use: Frameworks, data parsers, test fixtures with setup/teardown.
Intent: Provide a way to access elements of a collection sequentially without exposing its underlying representation. When to use: Custom collections, tree traversals, streaming data.
Design a multi-floor parking lot with different vehicle types, entry/exit gates, and billing. One of the most frequently asked LLD problems.
Design an elevator control system for a building with multiple elevators. Tests your ability to model state transitions and scheduling algorithms.
Design a library system that manages books, members, borrowing, returns, and fines. Focuses on clean entity modeling and business rules.
Design a two-player chess game. Tests inheritance hierarchies, move validation, and game state management.
Design a Snake and Ladder board game for multiple players. Simpler than chess but tests clean game-loop modeling.
Design an ATM system supporting withdrawal, deposit, balance inquiry, and PIN verification. Classic State pattern application.
Design a generalized board game (NxN tic-tac-toe or Connect Four). Tests clean abstractions and win-condition checking.
Design a hotel booking and management system. Tests reservation workflows, room allocation, and billing.
Design a ride-sharing service with riders, drivers, matching, trip lifecycle, and pricing. A complex, real-world system design scaled down to LLD.
Design an online movie ticket booking system with theaters, shows, seat selection, and payment. Tests concurrency and seat locking.
Design a food delivery platform with restaurants, menus, orders, delivery assignment, and tracking. Multi-entity coordination challenge.
Design an expense-sharing app with groups, expenses, split strategies, and balance settlement. Tests algorithmic thinking within LLD.
Design a vending machine that accepts coins/notes, dispenses products, and returns change. The canonical State pattern problem.
Design an online auction system with listings, bidding, auto-bid, and winner determination. Tests event-driven modeling and timing.
Design an order matching engine for a stock exchange. Tests data-structure selection and concurrent order processing.
Design a traffic light controller for a multi-way intersection. Tests state machines and timing coordination.
Design a configurable log parsing and aggregation system. Tests Chain of Responsibility and extensible architecture.
The foundational concurrency pattern where producers add items to a shared buffer and consumers remove them. BlockingQueue in Java handles synchronization internally.
Allows multiple concurrent readers but exclusive access for writers. Optimizes throughput when reads vastly outnumber writes.
Multiple approaches to making Singleton thread-safe in Java, each with different performance and laziness characteristics.
Using Semaphore to limit concurrent access to a resource. A practical concurrency primitive for rate limiting and connection pooling.
Using Java's ExecutorService framework to manage thread pools and dispatch tasks. The standard way to handle concurrency in production Java.
Visual catalog of all GoF patterns with UML diagrams, real-world analogies, and code examples in multiple languages.
Comprehensive Java tutorials covering OOP, design patterns, concurrency, Spring, and more with production-grade examples.
Pattern catalog with intent, structure, participants, and consequences. Great for quick revision before interviews.
Official Java tutorials covering language fundamentals, OOP, generics, concurrency, and the Collections framework.
Code smells and refactoring techniques. Essential for SOLID principle application and writing clean, maintainable code.
Deep dives into threads, locks, executors, CompletableFuture, and concurrent data structures in Java.