What is the Open/Closed Principle?

What is the Open/Closed Principle?

Let’s begin with a short summary of what the Open/Closed Principle is. It’s a principle for object oriented design first described by Bertrand Meyer that says that

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

At first thought that might sound quite academic and abstract. What it means though is that we should strive to write code that doesn’t have to be changed every time the requirements change. How we do that can differ a bit depending on the context, such as our programming language. When using Java, C# or some other statically typed language the solution often involves inheritance and polymorphism, which is what this example will illustrate.

Let’s say that we’ve got a Rectangle class. As most rectangles that I’ve encountered it has a width and a height.

public class Rectangle{

public double Width{get;set;}

publicdoubleHeight{get;set;}

}

Now our customer, wants us to build an application that can calculate the total area of a collection of rectangles. That’s not a problem for us. We learned in school that the area of a rectangle is it’s width multiplied with it’s height and we mastered the for-each-loop a long time ago.

public class AreaCalculator{

public double Area(Rectangle[] shapes){

double area =0;

foreach(var shape in shapes){

area += shape.Width*shape.Height;

}

return area;

}}

We present our solution, the AreaCalculator class to customer and he signs us his praise. But he also wonders if we couldn’t extend it so that it could calculate the area of not only rectangles but of circles as well.

That complicates things a bit but after some pondering we come up with a solution where we change our Area method to accept a collection of objects instead of the more specific Rectangle type. Then we check what type each object is of and finally cast it to it’s type and calculate it’s area using the correct algorithm for the type.

public double Area(object[] shapes){

double area =0;

foreach(var shape in shapes){

if(shape isRectangle){

Rectangle rectangle =(Rectangle) shape;

area += rectangle.Width*rectangle.Height;

}else{

Circle circle =(Circle)shape;

area += circle.Radius* circle.Radius*Math.PI;

}

}

return area;

}

The solution works and customer is happy.

Only, a week later he calls us and asks: “extending the AreaCalculator class to also calculate the area of triangles isn't very hard, is it?”. Of course in this very basic scenario it isn't but it does require us to modify the code. That is, AreaCalculator isn't closed for modification as we need to change it in order to extend it. Or in other words: it isn't open for extension.

In a real world scenario where the code base is ten, a hundred or a thousand times larger and modifying the class means redeploying it’s assembly/package to five different servers that can be a pretty big problem. Oh, and in the real world customer would have changed the requirements five more times since you read the last sentence :-)

One way of solving this puzzle would be to create a base class for both rectangles and circles as well as any other shapes that customer can think of which defines an abstract method for calculating it’s area.

public abstract class Shape{

public abstract double Area();

}

Inheriting from Shape the Rectangle and Circle classes now looks like this:

public class Rectangle:Shape{

publicdoubleWidth{get;set;}

publicdoubleHeight{get;set;}

publicoverridedoubleArea({

returnWidth*Height;

}

}

public class Circle:Shape{

publicdoubleRadius{get;set;}

publicoverridedoubleArea(){

returnRadius*Radius*Math.PI;

}

}

As we’ve moved the responsibility of actually calculating the area away from AreaCalculator’s Area method it is now much simpler and robust as it can handle any type of Shape that we throw at it.

public double Area(Shape[] shapes){

double area =0;

foreach(var shape in shapes){

area += shape.Area();

}

return area;

}

In other words we’ve closed it for modification by opening it up for extension.

If we look back our previous example, where did we go wrong? Clearly even our first implementation of the Area wasn’t open for extension. Should it have been? I’d say that it all depends on context. If we had had very strong suspicions that customer would ask us to support other shapes later on we could probably have prepared for that from the get-go. However, often it’s not a good idea to try to anticipate changes in requirements ahead of time, as at least my psychic abilities haven’t surfaced yet and preparing for future changes can easily lead to overly complex designs. Instead, I would suggest that we focus on writing code that is well written enough so that it’s easy to change if the requirements change.

Once the requirements do change though it’s quite likely that they will change in a similar way again later on. That is, if customer asks us to support another type of shape it’s quite likely that he soon will ask for support for a third type of shape.

So, in other words, I definitely think we should have put some effort into abiding by the open/closed principle once the requirements started changing. Before that, in most cases, I would suggest limiting your efforts to ensuring that the code is well written enough so that it’s easy to refactor if the requirements starts changing.

find more at here

要查看或添加评论,请登录

Vahid Farahmandian的更多文章

  • ???? ? ???? ?????? - ???? 1

    ???? ? ???? ?????? - ???? 1

    ?? ??? ????? ??? ????? ???? ? ???? ?????? ?? ???? ?????? ??????? ?? ???? ??? ????. ?? ?? ??? ??? ??????? ??? ?????? ???…

  • What's new in SQL Server 2017 Database Engine

    What's new in SQL Server 2017 Database Engine

    SQL Server 2017 represents a major step towards making SQL Server a platform that gives you choices of development…

  • TDD vs. ATDD vs. BDD

    TDD vs. ATDD vs. BDD

    Test-driven development (TDD) is a technique of using automated unit tests to drive the design of software and force…

  • What's In a Version Number, Anyway?

    What's In a Version Number, Anyway?

    Before getting into the article, I would like to say that the main author of this article is Jeff Atwood and I just…

  • Introduction to Pretotyping

    Introduction to Pretotyping

    Before anything I am so grateful from Alberto Savoia for his great article. This article is originally written by…

  • Lack of acceptable requirements discovery

    Lack of acceptable requirements discovery

    Write a scenario to cover the above process in software development area. If you are not working in software area, you…

  • Top 10 Most Popular .NET Tips of the Year

    Top 10 Most Popular .NET Tips of the Year

    Here are the 10 most popular tips of the year at Daily .NET Tips, based on the number of times they were viewed and…

社区洞察

其他会员也浏览了