Monday, November 8, 2010

[Tutorial] S.O.L.I.D. quality code in C#
Part3: Open Closed Principle (OCP)

The Open Closed Principle says that all software entities (like classes and methods) must be open for extension but closed for modification. This sounds odd, because those two rules seem to be contradictory. This article shows how to combine them and how to make your source code even more extensible and maintainable.

So how can a class or method at the same time be open for extension but closed for modification ?

A quick answer is : leave existing code unchanged and allow for extensions only by adding new code. This minimizes at the same time the possibility of regressions, behavior changes and bugs. The application gets more robust and provides a higher level of maintainability. Extension can be done without worrying about the overall stability of the application. All very good things !!!

But the code needs to be correctly structured to achieve this goal. Lets look an example, which shows the principle in action. In this example we start from an implementation that does not respect the Open Closed Principle. Then I apply the principle and you will see how the quality of the code will be ameliorated.

The current implementation contains a single class Shape with a property called ShapeType (possible values Square and Circle).

Fig3_OCP_Before

Furthermore, the application contains the method DrawAllShapes(…), that displays the different shapes on the screen.

Code_OCP

This approach has a major flaw: if new shapes are added, then existing code needs to be changed (ShapeType, DrawAllShapes, etc..). This makes the code hard to understand, to extend and to maintain over time.

So what could be the solution in this case ? In object oriented programming we know the concept of inheritance, which should be applied to avoid the necessity to change existing code.

The complete class design must be changed !

A new abstract class Shape with an abstract method Draw(…) should be created. Then different classes for each shape type, that inherit from the abstract Shape class, need to be defined. They contain the specific code that serves for the display on the screen.

Fig4_OCP_After

The DrawAllShapes(…) method must now be adapted and simplified in the last step. It should only contain the call to the Draw(…) method of objects that are treated.

Code_OCP_After

If you now get the business need to add a new shape type, you only need to create a new class that inherits from the abstract class and implement the special Draw behavior. So extensions become very easy to do. And you do not touch the existing structure anymore (or at least only in very rare cases).

When respecting this principle, your code gets correctly encapsulated, easily reusable and much simpler to maintain.


Share/Save/Bookmark

3 comments:

Fabrice Michellonet said...

Great article!

What about using an Iterface IShape instead of the abstract class, since we don't provide any base implementation?
I'm Nit-Picking, but i guess interfaces provide even more Open Close concept; Don't you?

Jason De Oliveira said...

Yes sure if the abstract class does not contain any implementation I fully agree, we need to use an Interface IShape. Goood remark !

Efim Zabarsky said...

Great article, thanks.

I think, you can add more information about meaning of abstractions (not only how implement it by using inheritance) - what is it and why is helps us.

Very good article!