Skip to main content

Chapter 5: Object-Oriented Programming

"OO is the ability, through the use of polymorphism, to gain absolute control over every source code dependency in the system."

๐ŸŽ“ For New Learnersโ€‹

What Does OOP Actually Give Us?โ€‹

The textbook answer is: encapsulation, inheritance, and polymorphism. Martin examines each and finds that the first two are either already available in non-OO languages or are actually weakened by OO languages. The real gift is polymorphism โ€” and specifically how OO makes it safe and convenient.

Encapsulation โ€” Already Existedโ€‹

C had perfect encapsulation before C++ existed:

  • Declare a struct and functions in a .h header file
  • Implement the struct internals in a .c file
  • Users of the header cannot see the implementation

C++ actually broke this by requiring member variables to be declared in the header (for compile-time sizing). Java and C# further weakened encapsulation by making all declarations visible in a single file.

Lesson: OO did not invent encapsulation. It packaged it more conveniently, but didn't improve it fundamentally.

Inheritance โ€” Available Before OOP (Just Awkward)โ€‹

Before OO, C programmers could achieve inheritance-like reuse by casting structs and overlapping memory layouts. OO made this more convenient and less error-prone.

Lesson: Inheritance is a convenience, not a capability breakthrough. And it comes with its own dangers (see LSP chapter).

Polymorphism โ€” The Real Giftโ€‹

Polymorphism means: a caller doesn't need to know which concrete implementation it's calling. In C, you could do this with function pointers โ€” but it was manual, risky, and error-prone. One wrong cast, and you get undefined behavior.

OO languages made polymorphism trivially safe. Define an interface; call through the interface; the runtime dispatches to the right implementation. No manual function pointer management.

This trivially safe polymorphism is the architectural breakthrough: it is the mechanism that lets you invert dependencies.

The Plugin Architectureโ€‹

Before polymorphism, the dependency structure of a program was dictated by the call graph:

main() โ†’ BusinessLogic โ†’ DatabaseDriver โ†’ MySQLLib

Everything pointed "downward" toward low-level implementation. Change the database, rewrite everything above it.

With polymorphism and dependency inversion:

BusinessLogic โ†’ DatabaseInterface โ† MySQLAdapter

The arrow between BusinessLogic and MySQLAdapter points the wrong way compared to the runtime call. At runtime, BusinessLogic calls the adapter. But at the source code level, BusinessLogic only knows about the interface. The adapter is a plugin โ€” swappable without touching BusinessLogic.


๐Ÿ”ฌ Senior Deep Diveโ€‹

Dependency Inversion as the Core OO Contributionโ€‹

Martin's argument is subtle and important: before OO, you could not safely invert source code dependencies. Function pointer-based polymorphism in C was possible but fragile. OO's contribution is making dependency inversion the default pattern, not the exceptional one.

The Dependency Inversion Principle (Chapter 11) follows directly: since OO gives us safe polymorphism, we can point every source code dependency in any direction we want. The natural direction should always be: toward stability and abstraction, away from volatility and concreteness.

The Power of Absolute Dependency Controlโ€‹

Martin's key statement deserves deep consideration:

"OO is the ability... to gain absolute control over every source code dependency in the system."

"Absolute control" means: no dependency is forced by the call graph. Every dependency is a choice. You can arrange them to create:

  • Business logic that has zero knowledge of databases, frameworks, or UI
  • Modules that are independently testable without starting the whole system
  • Components that can be deployed independently to separate services

This is the foundation of the entire Clean Architecture model.

Polymorphism in Java/Springโ€‹

The Spring framework itself is a massive exercise in OO polymorphism. ApplicationContext, BeanFactory, PlatformTransactionManager are all interfaces. The entire Spring ecosystem is a plugin architecture.

But Spring applications often underuse OO for their own domain logic:

// Concrete dependency โ€” breaks plugin architecture
@Service
public class OrderService {
@Autowired
private StripePaymentClient stripeClient; // concrete dependency!

public void charge(Order order) {
stripeClient.charge(order.getTotal()); // tied to Stripe forever
}
}

// Polymorphic โ€” enables plugin architecture
public interface PaymentGateway {
void charge(Money amount);
}

@Service
public class OrderService {
private final PaymentGateway paymentGateway; // depends on abstraction

public void charge(Order order) {
paymentGateway.charge(order.getTotal()); // Stripe? PayPal? Test double?
}
}

// In production
@Component
public class StripePaymentGateway implements PaymentGateway { ... }

// In tests
class FakePaymentGateway implements PaymentGateway {
public List<Money> chargedAmounts = new ArrayList<>();
public void charge(Money amount) { chargedAmounts.add(amount); }
}

The OrderService never changes when you switch payment providers. New providers are new plugins.

When to Use Inheritance vs Compositionโ€‹

Martin's treatment of inheritance is cautious. The architectural preference:

  • Inheritance: Use only for true IS-A relationships where LSP (Chapter 9) is satisfied. Avoid deep hierarchies.
  • Composition/delegation with interfaces: Prefer for behavioral variation. More flexible, less coupled.

Spring's own evolution reflects this: JdbcDaoSupport (extend it) was replaced by JdbcTemplate (inject it). Composition won.


Summaryโ€‹

PillarOO ContributionVerdict
EncapsulationConvenient packagingAlready existed; OO didn't improve it
InheritanceFormal mechanismUseful but dangerous; prefer composition
PolymorphismSafe, trivially convenientThe actual architectural breakthrough

The key insight: OO's value to architecture is safe polymorphism โ†’ dependency inversion โ†’ plugin architecture โ†’ independent deployability and testability.