Home Single Responsibility Principle
Post
Cancel

Single Responsibility Principle

There are five design principles and one among them is SRP (Single Responsibility Principle). it stated that Every class should have only one reason to change

What does it means the only one reason to change? When ever we see this statement it sound simple but very much confused.

Suppose I have a class and I want do modify it, At that particular moment, I have only one reason to change it and I am doing it what’s the problem and what’s the big deal?

That is where many people get confused. In order to make it simple, let me rephrase it in another way. A class should be created to do only one kind of job not many, So that, that class is expertize in doing that particular job.

As a real life example each individual is expert in one thing. For example plumber is very good in repairing the taps, TV repair guy know how to repair a TV. But plumber can learn the TV repair and he can repair the TV, but nobody believes plumber and give their TV to repair.

Similarly in OOPs its better to make a class expert in one thing.

Let’s see the example

1
2
3
4
5
6
class Person
{
public:
    void repairTap();
    void repairTelevision();
};

Now in this above example, we can see Person is doing two jobs and it breaks the SRP (Single Responsibility Principle). Its better to break and Person class into two classes namely Plumber and TVTechnician so each classes are expert in there own field.

New example

1
2
3
4
5
6
7
class Plumber
{
public:
    void repairTap();
    void repairValve();
    void fixPipeline();
};
1
2
3
4
5
6
class TVTechnician
{
public:
    void repairTelevision();
    void fixTelevisionDisplay();
};

The splitting of the classes into their respective job is called separation of concern

So, if we want to change the class Plumber my main reason or intent is to do something with plumping not with TV. That is your single reason to update the class.

Now, let see one more real time example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Document
{
public:
    Document(const std::string& name)
        : m_name(name)
    {

    }

    void write(const std::string content)
    {
        m_content = content;
    }

    std::string read() const
    {
        return m_content;
    }

    void save(const std::string& fileName)
    {
        std::ofstream f(fileName, std::ofstream::out);
        if (f.is_open())
            f << m_content << "\n";
    }

private:
    std::string m_name = "Untitled";
    std::string m_content = "";
};

int main()
{
    Document d("Resume");
    d.write("This is my resume");
    d.save("resume.txt");

    return 0;
}

Output

1
2
3
4
bhavith@bhavith:$ g++ hello.cpp 
bhavith@bhavith:$ ./a.out 
bhavith@bhavith:$ cat resume.txt 
This is my resume

In the above example we can see that Document class is trying to do two jobs

  • Operations w.r.t documents i.e. setting the name, writing and reading
  • Operations w.r.t to saving the documents

Since Document class is doing two jobs it is breaking SRP.

Suppose in future if we want to add one more function called saveAsPdf then we are keep on adding those kind of functionalities to Document and again it’s breaking the SRP.

The better way is to split the Document class into two, and make two experts to do their respective job correctly. One can be Document and another class can be PersistentManager

Let’s see how new example looks now

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <string>
#include <fstream>

class Document
{
public:
    Document(const std::string& name)
        : m_name(name)
    {

    }

    void write(const std::string content)
    {
        m_content = content;
    }

    std::string read() const
    {
        return m_content;
    }

private:
    std::string m_name = "Untitled";
    std::string m_content = "";
};

class PersistentManager
{
public:
    void save(const Document& doc, const std::string& fileName)
    {
        save(DocumentType::TXT, doc, fileName);
    }

    void saveAsPdf(const Document& doc, const std::string& fileName)
    {
        save(DocumentType::PDF, doc, fileName);
    }

private:
    enum class DocumentType {TXT, PDF,};

    void save(const DocumentType docType, const Document& doc,
        const std::string& fileName) const
    {
        std::string fileNameWithExtension = fileName;
        switch (docType)
        {
        case DocumentType::PDF:
            fileNameWithExtension += ".pdf";
            break;
        case DocumentType::TXT:
            fileNameWithExtension += ".txt";
            break;
        default:
            break;
        }

        std::ofstream f(fileNameWithExtension, std::ofstream::out);
        if (f.is_open())
            f << doc.read() << "\n";
    }
};

int main()
{
    PersistentManager pm;

    Document doc("Resume");
    doc.write("This is my resume");

    pm.save(doc, "resume");
    pm.saveAsPdf(doc, "resume");
    return 0;
}

Output:

1
2
3
4
5
6
bhavith@bhavith:$ g++ hello.cpp 
bhavith@bhavith:$ ./a.out 
bhavith@bhavith:$ cat resume.txt 
This is my resume
bhavith@bhavith:$ cat resume.pdf 
This is my resume

Can you see now, how the responsibility is split into two. Now you have only one reason or having one expert to do better job.

That is all about Single Responsibility Principle

This post is licensed under CC BY 4.0 by the author.

C++ concepts covered most

Rule of three in c++