Friday, April 25, 2008

Open Closed Principle (OCP)

Lets see a simple and elegant piece of code (read input from keyboard and write the contents to a file)

void Copy()
{
int c;

while( ( c = ReadKeyboard() ) != EOF )
{
WriteToFile(c);
}
}

It is/was considered elegant because each module hides lot of details from the user (of copy). One doesn't need to bother about how the keyboard works or what kind of keyboard it is etc, so is the same with writing to files.

The only issue with this piece of code is lack re usability. Ex: read from keyboard and write to a printer instead of a file (its rigid and immobile).

The interface Copy need to be modified to accommodate new requirement which potentially might break the existing functionality, that’s exactly what OCP attempts to avoid/attack.

Following is a modified code to accommodate new requirement (ability to write to a printer)

enum OutputDev { printer, file };

void Copy( OutputDev dev )
{
int c;

while( ( c = ReadKeyboard() ) != EOF )
{
if( dev == printer )
WriteToPrinter(c);
else
WriteToFile(c);
}
}

Let see what OCP says

A module (C++ entity) should be open for extension and closed for modifications --R. Martin (96)
OR
Modules should be written so they can be extended without requiring them to be modified --B. Mayer (88)

OCP says that, adding new types of a behavior should not happen at the cost of potentially modifying the existing behavior (modifications might introduce bugs).

The whole idea is to add new types of behavior by extending rather by modifying the current behavior so that new additions can guarantee no dents to current behavior.

An interface/public method defines the behavior of an object. Abstraction is a key concept which helps writing OCP compliant interfaces. C++'s polymorphism (static and dynamic) helps extending behavior to new types.

OCP only talks about adding/extending the behavior and not about modifying the original behavior itself . If there are any logical flaws in the existing code, they need to be fixed.

OCP adhering solution looks as below

// abstract reader interface
class ReaderAbstract{
public:
virtual int Read( ) = 0;
};

// abstract writer interface

class WriterAbstract{
public:
virtual void Write( int c ) = 0;
}

class SrcKeyboard: public ReaderAbstract {
public:
int Read()
{
// read a character from keyboard
}
};

class SrcFile: public ReaderAbstract {
public:
int Read()
{
// read a character from file
}
};

class TrgtFile: public WriterAbstract {
public:
void Write( int c )
{
// write a character to file
}
};

class TrgtPrinter: public WriterAbstract {
public:
void Write( int c )
{
// write a character to printer
}
};


void Copy ReaderAbstract & src, WriterAbstract & trgt )
{
int c;

while( ( c = src.Read() ) ! = EOF )
trgt.Write( c );
}

Because the abstract interface allowed us easily adding new type of source and target without modifying the current code, we can say that our design is closed against modifications.

But it may not always be possible to close a design w.r.t potential modifications. OCP gives a breather here in form of strategic closure (partial OCP).

Strategic closure says that if full OCP is not possible, identify areas of an interface which can't be closed 100% against modifications, minimize its scope and document the same . Domain knowledge, design experience comes handy in figuring out where and how to apply strategic closure .

OCP Heuristics

  • Never make data members public as they might result in potential tight dependency in form of derived classes (if they are playing with the base public data members)
  • Global variables are dangerous (same as public data members)
  • RTTI, switch statements could be dangerous (mostly they work with types and adding new type might require changes to the code to accommodate the new types)
  • Based on circumstances and need basis, exceptions apply to OCP too (For example: globals are the only option to share vital information etc). Be very cautious before thinking of taking an exception from OCP


References

Design Principles and Design Patterns - PDF
The Open Closed Principle - PDF
The Open Close Principle - one more
OCP (DDJ)
Open/Closed Principle - wikipedia
The Open Closed Principle - Doodle Project
Principles of Object Oriented Design - PPT
Advanced Principles of OO Class Design - PPT


Previous Topic:

OO Design principles, an Intro

No comments: