Open-Closed Principle

Open-Closed Principle

Software entities (classes, modules, functions, components, etc.) should be open for extension, but closed for modifications.

Extension: Extending the behavior of a module.

Modification: Changing the code of a module.

Extension and Modification

Why is it important to be closed for modifications?

Open for extension means that when requirements of the application change, we can extend the module with new behaviors that reflect those changes. We change what the module does.

Closed for modification means that changes in behavior do not result in changes in the module's source or binary code.

Several reasons for closing modules against changes:

Abstraction is the Key

Abstraction is the Key

To enable extending an entity without modifying it, abstract over subparts of its behavior.

Many programming languages allow to create abstractions that are fixed and yet represent an unbounded group of possible behaviors!

Different kinds of abstraction mechanisms exist:

In the following, we shortly discuss the two main ways of abstracting over variability in object-oriented programs.

Abstracting Over Variations

OCP Container

Abstracting Over Variations

OCP Container LayoutManager

Understanding the Open-Closed Principle

A Possible Design for Drawable Shapes

OCP Shape

Consider an application that draws shapes - circles and rectangles – on a standard GUI.

OCP SketchVectorDrawingApp

Implementation of the drawing functionality:

class Application {
  public void drawAllShapes(List<Shape> shapes) {
    for(Shape shape : shapes) {
      switch(shape.getType()) {
      case Circle:
        drawCircle((Circle)shape);
        break;
      case Rectangle:
        drawRectangle((Rectangle)shape);
        break;
  } } }

  private void drawCircle(Circle circle) { ... }

  private void drawRectangle(Rectangle rectangle) { ... }
}

Does this design conform to the open-closed design principle?

Evaluating the proposed design:

Rigid, Fragile and Immobile Designs

  • Rigid designs are hard to change – every change causes many changes to other parts of the system.

  • Fragile designs tend to break in many places when a single change is made.

  • Immobile designs contain parts that could be useful in other systems, but the effort and risk involved with separating those parts from the original system are too big.

When we evaluate our design, does it show signs of rigidity, fragility or immobility?

Evaluating the Design

  • Our design is rigid, fragile and immobile.

  • The proposed design violates the open-closed design principle with respect to extensions with new kinds of shapes.

  • We need to close our module against this kind of change by building appropriate abstractions.

Assessing our design w.r.t. its rigidity, fragility and immobility:

Refined Design for Drawable Shapes

OCP ShapeOCPConformDesign

Evaluating the Extensibility

This solution complies to the open-closed design principle.

This unconditional statement is – of course – not correct. It is not possible to be open for all kinds of extension and also be closed for modification.

Other Kinds of Changes

OCP ShapeOCPConformDesign

These abstractions are more of an hindrance to several other kinds of changes.

Abstractions May Support or Hinder Change!

Abstractions Reflect a Viewpoint

Abstractions Reflect a Viewpoint

No matter how “closed” a module is, there will always be some kind of change against which it is not closed.

On the "Natural" Model Structure

Imagine: Development of a "Zoo Software".

Three stakeholders:

  • Veterinary surgeon: What matters is how animals reproduce!
  • Trainer: What matters is the intelligence!
  • Keeper: What matters is what they eat!

One Possible Class Hierarchy When Modeling Animals

OCP Animals

When we consider the classes Oviparous and Mammal it is obvious that the class hierarchy reflects the veterinary surgeon's understanding.

The Animal World From a Trainer's Viewpoint

“The show shall start with the pink pelicans and the African geese flying across the stage. They are to land at one end of the arena and then walk towards a small door on the side. At the same time, a killer whale should swim in circles and jump just as the pelicans fly by. After the jump, the sea lion should swim past the whale, jump out of the pool, and walk towards the center stage where the announcer is waiting for him.”

OCP Animals Show

Models Reflecting Different Viewpoints Overlap

OCP Animals Viewpoints

Current programming languages and tools do not well support modeling the world based on co-existing viewpoints.

Using a programming language which offers more advanced modeling mechanisms, it may be possible to create a design that more closely models the presented world.

Strategic and Agile Closure

Strategic Closure

  • Choose the kinds of changes against which to close your module.

    • Guess at the most likely kinds of changes.
    • Construct abstractions to protect against those changes.
  • Prescience derived from experience:

    • Experienced designers hope to know the user and an industry well enough to judge the probability of different kinds of changes.
    • Invoke open-closed principle against the most probable changes.

Be Agile

Recall that guesses about the likely kinds of changes to an application over time will often be wrong.

Conforming to the open-closed principle is expensive:

  • Development time and effort to create the appropriate abstractions
  • Created abstractions might increase the complexity of the design.

    • Needless, Accidental Complexity.
    • Incorrect abstractions supported/maintained even if not used.

Be agile: Wait for changes to happen and close against them.

Takeaway

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modifications.

Bertrand Meyer, 1988

  • Abstraction is the key to supporting the open-closed design principle.
  • No matter how “closed” a module is, there will always be some kind of change against which it is not closed.