• Skip to main content
  • Skip to primary sidebar

Technical Notes Of
Ehi Kioya

Technical Notes Of Ehi Kioya

  • About
  • Contact
MENUMENU
  • Blog Home
  • AWS, Azure, Cloud
  • Backend (Server-Side)
  • Frontend (Client-Side)
  • SharePoint
  • Tools & Resources
    • CM/IN Ruler
    • URL Decoder
    • Text Hasher
    • Word Count
    • IP Lookup
  • Linux & Servers
  • Zero Code Tech
  • WordPress
  • Musings
  • More
    Categories
    • Cloud
    • Server-Side
    • Front-End
    • SharePoint
    • Tools
    • Linux
    • Zero Code
    • WordPress
    • Musings

SOLID Design Principles in C#: Part 2 – Open/Closed Principle

Tagged: .Net, C#, Coding Practices, Coding Right, Design Principles, Right design, SOLID

  • This topic has 0 replies, 1 voice, and was last updated 2 years, 5 months ago by Aruorihwo.
Viewing 1 post (of 1 total)
  • Author
    Posts
  • February 26, 2020 at 10:32 am #86687
    Spectator
    @aruorihwo

    SOLID Design Principles in C#

    Part 1 of this article talked about Single Responsibility principle which is the ‘S’ in the popular SOLID Design Principles. This article will talk about the next principle – the Open/Closed principle. We will be discussing what that means practically, when it applies and when it does not. We will also be discussing how far we should take it. SOLID principles apply to any programming language, but we would be using C# for our examples in this article.

    O – Open/Closed Principle

    Open/Closed principle states that software entities such as classes, modules, functions and all must be open for extension but closed for modification. Robert C. Martin regarded the Open/Closed principle as “the most important principle of object-oriented design”

    The idea of Open/Closed principle is very simple. You have a code that is successfully working in the production environment, but because of a change you want to make, you end up changing this code and introducing bugs to it. You have then endangered what you already have working because you want to make a modification. That is exactly what Open/Closed principle is trying to avoid – if it isn’t broken don’t modify it in such a way that new bugs are added to it. Let’s look at an example below

    Perimeter Calculator

    Let’s say we have a client called Ameyo. Ameyo has come to us that she requires a simple calculator for calculating the sum total perimeter of collection of triangles. This seems a fairly simple request. So, we first create a Triangle class.

    
    public class Triangle
    {
    	public double Base {get; set;}
    	public double LeftSide {get; set;}
    	public double RightSide { get; set; }
    }
    

    Then, we create a PerimeterCalaculator class to handle the calculation of perimeter of the collection of triangles sent to the method as a parameter. A simple foreach would do to make our solution work beautifully.

    
    public class PerimeterCalculator()
    {
    	public double Calculate(Triangle[] triangles)
    	{
    		var totalPerimeter = 0;
    		foreach(var triangle in triangles)
    		{
    			var perimeter = triangle.Base + triangle.LeftSide + triangle.RightSide;
    			totalPerimeter += perimeter;
    		}
    		
    		return totalPerimeter;
    	}
    }
    

    Ameyo is thoroughly impressed with our work and begins using the solution and getting the results she wants. But, the next week, she is back, asking if we could add rectangles to the list of shapes.
    The truth is the request is no big deal. After all, we are geniuses. Our code might get a little more complicated, but we know we can pull it off. So, we add another class for rectangles called the Rectangle class.

    
    public class Rectangle
    {
    	public double Length { get; set; }
    	public double Breadth { get; set; }
    }
    

    However, adding a new class does not solve the situation. We would then need to modify the Perimeter calculator class to accommodate the new shape that maybe passed as a parameter to the calculate method.

    
    public class PerimeterCalculator()
    {
    	public double Calculate(object[] shapes)
    	{
    		var totalPerimeter = 0;
    		foreach(var shape in shapes)
    		{
    			if(shape is Triangle triangle)
    			{
    				var perimeter = triangle.Base + triangle.LeftSide + triangle.RightSide;
    				totalPerimeter += perimeter;
    			}
    			if(shape is Rectangle rectangle)
    			{
    				var perimeter = rectangle.Length + rectangle.Breadth;
    				totalPerimeter += perimeter;
    			}
    		}
    		
    		return totalPerimeter;
    	}
    }
    

    Now, we have the exact solution Ameyo wants and all is well once again. Until a week later, when she comes and asks if we can add circles to the shapes in which their perimeter is calculated.

    I know it seems that to add an extra shape isn’t going to be that much of a big deal, but picture a real life scenario, where the calculations and processes are 100x this and changes are requested regularly, this would be a very big issue. Why? It is because our code violates the Open/Closed principle. Which implies that our code is not scalable or extensible. Also, we must keep making changes to an already existing and working code, a mistake would cause the whole house of cards to come crashing down. That is unacceptable in a production environment.

    Applying the Open/Closed Principle

    The Open/Closed principle usually sounds very academic and a bit abstract. But we have seen a scenario where we can apply the principle and save ourselves a lot of head and heart aches. This principle makes us endeavor to write our code such that it does not have to be changed every time requirements change. Sounds impossible? Well it isn’t. In C# and other similar languages, to apply this principle usually involves inheritance, polymorphism and implementing interfaces. Let’s see how we can use some of these concepts for our code.

    The simplest way of applying this principle and solving this problem is to create a base Shape class that can be inherited and overridden if need be. This class would be the base for the shapes Ameyo has requested and any other shape Ameyo can request or create. Here’s how the Shape class looks:

    
    public abstract class Shape
    {
    	public abstract double Perimeter();
    }
    
    

    This is looks perfect! All other shape classes can then inherit from this base class and implement their own perimeter calculation.

    
    public class Triangle : Shape
    {
    	public double Base {get; set;}
    	public double LeftSide {get; set;}
    	public double RightSide { get; set; }
    
    	public override double Perimeter()
    	{
    		var perimeter = Base + LeftSide + RightSide;
    		return perimeter;
    	}
    }
    
    public class Rectangle : Shape
    {
    	public double Length { get; set; }
    	public double Breadth { get; set; }
    
    	public override double Perimeter()
    	{
    		var perimeter = Length + Breadth;
    		return perimeter;
    	}
    }
    
    public class Rectangle : Shape
    {
    	public double Length { get; set; }
    	public double Breadth { get; set; }
    
    	public override double Perimeter()
    	{
    		var perimeter = Length + Breadth;
    		return perimeter;
    	}
    }
    
    public class Circle : Shape
    {
    	public double radius { get; set; }
    	
    	public override double Perimeter()
    	{
    		var perimeter = 2 * Math.PI * radius;
    		return perimeter;
    	}	
    }
    

    The perimeter calculator class can then be light weight and extensible as shown below:

    
    public double Perimeter(Shape[] shapes)
    {
        double perimeter = 0;
        foreach (var shape in shapes)
        {
            perimeter += shape.Perimeter();
        }
    
        return perimeter;
    }
    

    We can keep extending and extending the application to take as much shapes as we want. This is because we have moved the responsibility of calculating the perimeter from the PerimeterCalculator class to the individual shapes, thereby opening up our application to extensibility. This means, just like the Open/Closed principle, our application is closed for modification but open for extension.

    Open/Closed Principle – Applying Balance

    It is very usual for people to go overboard once the hear of a principle or technique, but it is very important for us to maintain balance. So, the question is, when do we use this principle?

    Let’s use our example as a case study. It is very obvious that our first implementation of a solution to Ameyo’s requirements didn’t follow the principle. But, should it have been? I believe a general advice to this question is to examine the context. Are we expecting extensions to a module or solution from the client? You may know based on previous encounters with the client or with the problem, but I don’t advise you assume or anticipate requirement changes. If you do expect extensions, then apply the principle. Otherwise, I suggest you pay more attention to writing good and properly structured code that you can easily change if the requirements change. But once they change, you should definitely do the work required to make your code abide to the principle because requirements would most like change again in a similar way once they do change.

  • Author
    Posts
Viewing 1 post (of 1 total)
  • You must be logged in to reply to this topic.
Log In

Primary Sidebar

FORUM   MEMBERSHIP

Log In
Register Lost Password

POPULAR   FORUM   TOPICS

  • How to find the title of a song without knowing the lyrics
  • How To Change Or Remove The WordPress Login Error Message
  • The Art of Exploratory Data Analysis (Part 1)
  • Welcome Message
  • Replacing The Default SQLite Database With PostgreSQL In Django
  • Getting Started with SQL: A Beginners Guide to Databases
  • How to Implement Local SEO On Your Business Website And Drive Traffic
  • About
  • Contact

© 2022   ·   Ehi Kioya   ·   All Rights Reserved
Privacy Policy