The SOLID Principles (p. 141)

SOLID is a mnemonic acronym for five agile design principles that are intended to make software design more understandable and adaptable to requirements change. The SOLID principles are a subset of many principles promoted by Uncle Bob.

Note: only the SRP and OCP were covered in class.

Single Responsibility Principle

Single Responsibility Principle


A class should have one and only one reason to be changed.

  • who is the code responsible to?
  • who must the design of the code respond to?

This does not apply to bug fixes and refactoring - those are the responsibility of the programmer, not the code.

The SRP is closely related to cohesion and coupling.

  • Cohesion is the degree to which the elements contained in a module belong together, mostly from the functional perspective.
  • The elements in a cohesive module should change for the same reason.
    • with 2+ responsibilities in one module, changes to one may impair or inhibit the others
  • well-aligned with separation of concerns (4.1.6)
public class RetirementAccount() {
    public void compileReport();
    public void printReport();
}

This class could be changed for

  • the content of the report
  • the format of the report (HTML, XML, etc)

These are separate responsibilities, so should be in separate classes.

Open-Closed Principle

Open-Closed Principle


Software modules should be open for extension, but closed for modification.

A subclass may

  • extend a superclass through inheritance (open for extension)
  • override an inherited method without the need to change or recompile the superclass (closed for modification)

Polymorphic Open-Closed Principle


Extension should not result in changes to the source or binary code of the existing superclass or clients of the superclass.

Example: Closed Shape vs. Open Shape (p. 143):

General idea:

  • several classes (Line, Circle, etc.) extend Shape.
  • Some shapes have a calculateArea() method, others don't.
  • class Diagram has an ArrayList<Shape> with the following loop:
for (Shape shape : shapes) {
    if (shape instanceOf Circle)
        totalArea += (Circle) shape.calculateArea();
    else if (shape instanceOf Square)
        totalArea += (Square) shape.calculateArea();
}

What if we need to add a new shape?

  • doesn't affect Shape
  • does affect Diagram, a client of Shape
    • this violates the OCP

Problem: inadequate classification of Shape objects

  • some have area, others don't

Possible solutions:

  • Create separate ClosedShape abstract class with calculateArea() method
  • Give Line calculateArea() method, return 0

When creating a class design that complies with the OCP, it's vital to anticipate likely changes. It allows us to invent an abstraction to protect the change from affecting the existing classes.