Click here to Skip to main content
15,867,686 members
Articles / General Programming / Architecture

SOLID Principles: Single Responsibility Principle -> What, Why and How.

Rate me:
Please Sign up or sign in to vote.
4.87/5 (17 votes)
27 Jun 2013CPOL2 min read 86.9K   38   6
SOLID principles: Single Responsibility Principle, a simple example in C#

Image 1 

Introduction 

This article will give an explanation of the Single Responsibility Principle (SRP) and will show a simple example in C#.

Background

What

There should never be more than one reason for a class to change. The SRP is one of the simplest of the SOLID principles but also one of most difficult to get right. Collecting and gathering responsibilities at one place is a common thing to do and happens in a natural way. Finding and separating those responsibilities from one another is much of what software design is really about.

Why

When a class has more than one responsibility, there are also more triggers and reasons to change that class. A responsibility is the same as “a reason for change” in this context. Changes to one responsibility may impair or inhibit the class’ ability to meet the others. This kind of coupling leads to fragile designs that break in unexpected ways when changed. If a class has more than one responsibility, then the responsibilities become coupled. Also when a (functional) responsibility is divided over more than one class, all classes part of that responsibility have to changed. They are caught in the chain of change. Always try to give every class its own and unique responsibility.

How

Separating responsibility can be done by defining for every responsibility a class or an interface. It makes no difference, a class can be seen as nothing more than a container of code, like a file or a library. What's important is that responsibilities are separated by abstraction and therefore can be implemented by different consumers of that interface.

Using the Code

The following C# example shows a class named "RectangleShape" that implements two methods, one that calculates its rectangle area and one that draws the rectangle. When the area calculation changes for some reason or the drawing method has to change, for example, another fill color is used, then the whole class is under change. Also if the properties are altered, it influences both methods. After a code change, the class must be tested as a whole again. There is clearly more than one reason to change this class.

Problem

C#
/// <summary>
/// Class calculates the area and can also draw it on a windows form object.
/// </summary>

    public class RectangleShape
    {
        public int Height{ get; set; }
        public int Width { get; set; }
 
        public int Area()
        {
            return Width * Height;
        }
 
        public void Draw(Form form)
        {
            SolidBrush myBrush = new SolidBrush(System.Drawing.Color.Red);
            Graphics formGraphics = form.CreateGraphics();
            formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, Width, Height);
        }
    }   

Typically, the above class is used by consuming client classes like these:

C#
/// <summary>
/// Consumes the RectangleShape */
/// </summary>
    public class GeometricsCalculator
    {
        public void CalculateArea(RectangleShape rectangleShape)
        {
            int area = rectangleShape.Area();
        }
    }   


/// <summary>
//// Consumes the RectangleShape */
/// </summary>
    public class GraphicsManager
    {
        public Form form {get;set;}

        public void DrawOnScreen(RectangleShape rectangleShape)
        {
            rectangleShape.Draw(form);
        }
    }

Solution

The next classes show how to separate the different responsibilities. Basic coding is used not taking other SOLID principles into account. It only just shows how to deal with the SRP principle. The RectangleDraw class consumes now a RectangleShape instance and a Form object.

C#
/// <summary>
/// Class calculates the rectangle's area.
/// </summary>
    public class RectangleShape
    {
        public int Height { get; set; }
        public int Width { get; set; }

        public int Area()
        {
            return Width * Height;
        }
    }

/// <summary>
/// Class draws a rectangle on a windows form object.
/// </summary>
    public class RectangleDraw
    {
        public void Draw(Form form, RectangleShape rectangleShape)
        {
            SolidBrush myBrush = new SolidBrush(System.Drawing.Color.Red);
            Graphics formGraphics = form.CreateGraphics();
            formGraphics.FillRectangle(myBrush, 
            new Rectangle(0, 0, rectangleShape.Width,rectangleShape.Height));
        }
    }

The following code shows how to consume both classes:

C#
/// <summary>
/// Consumes the RectangleShape */
/// </summary>
    public class GeometricsCalculator
    {
        public void CalculateArea(RectangleShape rectangleShape)
        {
            int area = rectangleShape.Area();
        }
    }

/// <summary>
/// Consumes the RectangleDraw and RectangleShape */
/// </summary>
    public class GraphicsManager
    {
        public Form form { get; set; }
        
        public void DrawOnScreen(RectangleDraw rectangleDraw, RectangleShape rectangleShape)
        {
            rectangleDraw.Draw(form, rectangleShape);
        }
    }      

Have fun!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Rood Mitek
Netherlands Netherlands
Christian Vos .MCSD has been an independent Microsoft developer since 1999 and is specialized in distributed Microsoft .Net platform based Web applications. He is founder of the company Rood Mitek which has developed applications for companies like Philips Electronics, ASML, Lucent Technologies, Amoco, AT&T etc.

Comments and Discussions

 
GeneralThis is a good article with helpful examples Pin
Daniel Miller19-Aug-15 9:56
professionalDaniel Miller19-Aug-15 9:56 
GeneralMy vote of 3 Pin
girishmeena5-Aug-15 8:48
girishmeena5-Aug-15 8:48 
QuestionWhere People Get Confused Pin
giantism5427-Jun-13 7:21
giantism5427-Jun-13 7:21 
QuestionWhat is the advantage of the second example? Pin
Klaus Luedenscheidt26-Jun-13 19:00
Klaus Luedenscheidt26-Jun-13 19:00 
AnswerRe: What is the advantage of the second example? Pin
Christian Vos26-Jun-13 22:09
Christian Vos26-Jun-13 22:09 
Hey Klaus,

Thanks for the comment.
When the height and width property value changes, it is of course no problem for both classes but when
I want to change how the the area is calculated regarding the existing properties in the rectangle, I have to change the designated class for this and that is the RectangleShape class.
I don't have to change the RectangleDraw class and therefore this class is outside the scope of this change.
So this class does not have to be tested or deployed after an area calculation change.
In the first example when the RectangleShape class is changed, then the draw functionality is also affected because it is in the same class. When a class is changed, all functionality in that class is in a danger zone of being altered and therefore a potential bug can be introduced in the draw method.
That is the difference between the two examples.
Because the example is so simple it looks trivial but when classes are filled with different complex functionality is becomes more clear.

Christian
GeneralRe: What is the advantage of the second example? Pin
Paulo Zemek27-Jun-13 6:19
mvaPaulo Zemek27-Jun-13 6:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.