Common Object‑Oriented Design Principles: SOLID, Dependency Inversion, Interface Segregation, Composite Reuse, and the Law of Demeter
This article summarizes the most widely used object‑oriented design principles—including the five SOLID rules, the Composite/Aggregate Reuse Principle, the Law of Demeter, and related guidelines—explaining their definitions, analyses, advantages, and practical examples for improving software modularity and maintainability.
1. Development Principles
The classic object‑oriented design principles, regardless of programming language, provide guidance for system design and development. This article summarizes these common principles and explains their significance.
The basic SOLID principles consist of five rules, often supplemented by the Law of Demeter and the Composite/Aggregate Reuse Principle, resulting in six or seven widely referenced principles.
2. S – Single‑Responsibility Principle (SRP)
Each class should have only one reason to change, meaning it should perform a single responsibility. This promotes low coupling and high cohesion by encapsulating a single responsibility within a class.
1. Definition
Every object should have a single responsibility, fully encapsulated by the class, i.e., only one cause for the class to change.
2. Principle Analysis
The more responsibilities a class (or module, method) has, the less reusable it becomes, and changes to one responsibility may affect others. Responsibilities are divided into data responsibilities (attributes) and behavior responsibilities (methods).
Applying SRP leads to high cohesion, low coupling, clearer class responsibilities, improved readability, easier maintenance, and reduced risk of change.
3. Advantages
Reduced class complexity and clear responsibilities.
Improved readability and maintainability.
Changes affect only the relevant class, enhancing extensibility.
4. Example
Separation of Entity, DAO, Service, Controller, and Util classes in a Spring MVC application.
3. O – Open‑Closed Principle (OCP)
Software entities (classes, modules, functions) should be open for extension but closed for modification.
1. Definition
A system should allow new behavior to be added without changing existing source code, achieved through abstraction.
2. Principle Analysis
When requirements change, extend existing entities rather than modify them, preserving stability. Abstract classes and interfaces define the contract; concrete implementations are extended.
3. Example
Template Method and Observer patterns illustrate the Open‑Closed Principle.
4. L – Liskov Substitution Principle (LSP)
Objects of a superclass must be replaceable with objects of a subclass without altering program correctness.
1. Definition
If any object of type S can be substituted by an object of type T such that programs using T behave identically, then S is a subtype of T.
2. Principle Analysis
The principle ensures that subclass instances can be used wherever base class instances are expected, preserving behavior and avoiding runtime errors.
5. I – Interface Segregation Principle (ISP)
Clients should not be forced to depend on interfaces they do not use.
1. Definition
Split large interfaces into smaller, role‑specific ones so that clients only need the methods they require.
2. Principle Analysis
Each interface represents a single role.
Provide only the behavior needed by the client.
Combine with SRP to keep interfaces cohesive and minimal.
6. D – Dependency Inversion Principle (DIP)
High‑level modules should not depend on low‑level modules; both should depend on abstractions.
1. Definition
Abstractions must not depend on details; details must depend on abstractions. Program to interfaces, not implementations.
2. Principle Analysis
Using abstract classes or interfaces decouples high‑level logic from concrete implementations, enabling flexible extensions.
3. Example 1
Dependency relationships in UML are shown as dashed arrows from the dependent to the depended‑upon element.
4. Example 2
A data conversion module that supports multiple source types (DatabaseSource, TextSource) and target formats (XMLTransformer, XLSTransformer) can be refactored with DIP to avoid modifying the main class when adding new sources or formats.
7. Composite/Aggregate Reuse Principle (CARP)
Prefer object composition over inheritance to achieve reuse.
1. Definition
Use object composition (or aggregation) rather than inheritance to reuse existing functionality.
2. Principle Analysis
Inheritance offers static reuse but reduces encapsulation and flexibility.
Composition provides lower coupling, selective behavior, and runtime flexibility.
Composition is generally preferred unless inheritance is clearly justified and Liskov Substitution is satisfied.
8. Law of Demeter (LoD)
Minimize knowledge of other classes to reduce coupling.
1. Definition
Also known as the Least Knowledge Principle: a class should only talk to its immediate friends (itself, method parameters, its own fields, objects created within the method, or elements of a field collection).
2. Analysis
Limiting interactions lowers coupling, improves reuse, and makes changes less risky.
3. Example
Facade pattern and Mediator pattern illustrate LoD in practice.
9. Q&A
1. Other object‑oriented design principles?
Encapsulation of change, favor composition over inheritance, program to interfaces, design for loose coupling, keep classes closed for modification (OCP), depend on abstractions (DIP), talk only to friends (LoD), and ensure a class has a single reason to change (SRP).
2. Explain Liskov Substitution Principle
Strict definition: substituting any instance of a subtype for a base type must not alter program behavior. Informal definition: wherever a base class is used, a subclass can be used transparently.
3. When is the Law of Demeter violated?
When a class communicates with “strangers” (objects it does not directly own or know), increasing coupling.
4. Example of a design pattern that follows the Open‑Closed Principle
The Strategy pattern (e.g., Java’s Collections.sort() using a Comparator) allows new strategies to be added without modifying existing sorting code.
5. When to use the Flyweight pattern?
When many identical immutable objects are needed; sharing them reduces memory usage (e.g., Java String, Integer, and Long pools).
Original source: https://www.cnblogs.com/pengdai
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.