Click here to Skip to main content
16,019,873 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 89.6K   40   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 
GeneralRe: What is the advantage of the second example? Pin
Paulo Zemek27-Jun-13 6:19
Paulo Zemek27-Jun-13 6:19 
Christian, I should say that I agree with Klaus.
I know the principle and I even wrote an article myself about it (well, not directly about it, but you can see at: Attributes vs. Single Responsibility Principle[^]).

But in your example, it really looks like any method should be in a different class.
In fact, the problem presented by Klaus (changing Width and Height to double) will affect two classes now, so the RectangleShape may follow SRP (it only changes by its own changes) but the RectangleDraw will change if it needs to change how to draw or if the RectangleShape changes.

I think that you should use a better example. In fact, by using a Rectangle type as a parameter to draw your RectangleShape, it looks like something is broken. I know it is an example and that you used an already existing method that requires a Rectangle instance, but I think you should use a better example that will not conflict with existing types.

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.