SOLID: five principles for maintainable object-oriented design
On this page 6 headings
SOLID is a set of object-oriented principles for software design, conceptualised by Robert Martin (“Uncle Bob”), one of the founders of the Agile Manifesto. They make code easy to understand and modular, and support good cohesion and loose coupling. S = Single Responsibility, O = Open–Closed, L = Liskov Substitution, I = Interface Segregation, D = Dependency Inversion.
2.1 S — Single Responsibility Principle (SRP)
Every class should have a single responsibility/purpose. The original Seller class held seller ID, name, address and product, and had addSeller, deleteSeller, addProduct, and add/delete/view inventory.
Split it into Seller (seller details, addSeller, deleteSeller), Product, and Inventory (takes seller ID; products are added to the seller’s inventory). This lets Product change without major changes to Seller/Inventory, and makes mistakes easier to find because the code is isolated.
2.2 O — Open–Closed Principle (OCP)
Software entities should be open for extension, closed for modification: extend behaviour, e.g. through subclasses, without modifying existing classes. Product has ID, name, type and cost. Adding size/colour and a new addProduct to Product violates OCP.
Instead, create Clothing extending Product with size and colour. A Book subclass with author and publisher is added the same way.
2.3 L — Liskov Substitution Principle (LSP)
LSP applies to inheritance hierarchies. “Derived classes should be substitutable by their base class”: if D is a subtype of B, we can replace B with D without interrupting the behaviour of the program. The feature is to notify sellers about feedback on their product by email.
Abstract class FeedbackNotification has abstract notify(product, feedback, email); EmailNotification extends it. Adding SMSNotification breaks this: it needs a mobile number, not an email, so the derived method cannot substitute the base one.
Fix: remove email from the abstract notify(product, feedback). EmailNotification takes email in its constructor; SMSNotification takes mobile number and carrier in its constructor. Both implement notify(product, feedback).
2.4 I — Interface Segregation Principle (ISP)
An interface is a group of related methods with empty bodies; it specifies what, not how. Other classes implement it by implementing all its methods. Interface Segregation: “do not force any client to implement an interface which is irrelevant to them”. DeliveryProcessing defines placeOrder(), notifySeller(), packageOrder(), deliver(). An online/e-book order does not need packaging or delivery to an address, so the last two methods are irrelevant to it.
Split it into PhysicalDeliveryProcessing (placeOrder, notifySeller, packageOrder, deliver) and OnlineDeliveryProcessing (placeOrder, notifySeller, provideDownloadLink(Product p, String url)). Each client implements only the interface it needs.
2.5 D — Dependency Inversion Principle (DIP)
Prefer abstractions/interfaces over implementations; always associate classes with interfaces rather than actual implementations. A seller should receive payment for products sold. Seller has a BankAccount attribute with number, branch and balance. Adding Paytm, Google Pay or UPI would mean adding more attributes, so Seller is tightly coupled and the code gets complex.
Fix: interface PaymentAccount with payment(); BankAccount, UPI, GooglePay and Paytm implement it; Seller is coupled to PaymentAccount. In main, create the chosen payment object (e.g. BankAccount, later UPI) and pass it to the seller.
2.6 How the principles differ
SRP asks whether a class has a cohesive job. OCP asks how expected new behavior can be added. LSP asks whether a subtype honors its parent contract. ISP asks whether a client is forced to use irrelevant methods. DIP asks whether important business logic depends on a concrete detail instead of a stable abstraction.
| Principle | Main warning sign | Typical improvement |
|---|---|---|
| SRP | One class changes for unrelated reasons | Separate responsibilities |
| OCP | Adding a product type means editing the existing Product class | Provide extension points |
| LSP | Subclass cannot substitute the base method (e.g. notify needs email) | Preserve base contract |
| ISP | Client must implement irrelevant methods (e-book: packageOrder, deliver) | Split interfaces by client needs |
| DIP | Business code creates a specific provider | Depend on an abstraction |
Follow these principles to make code more efficient, maintainable and easy to understand; they recur in design patterns.
