Question

Can someone give me an example of the Single Responsibility Principle? I am trying to understand what it means, in practice, for a class to have a single responsibility as I fear I probably break this rule daily.

Was it helpful?

Solution

Check out the Solid description.

Unless you ask for something more specific, it will be hard to help more.

Single responsibility is the concept of a Class doing one specific thing (responsibility) and not trying to do more than it should, which is also referred to as High Cohesion.

Classes dont often start out with Low Cohesion, but typically after several releases and different developers adding onto them, suddenly you'll notice that it became a monster or God class as some call it. So the class should be refactored.

Its hard to think of a good example, but one I can think of recently would be a class we have that manages different packet processing stages, a type of Chain of Responsibility. The initial intention of this class was to maintain a list of stages and to orchestrate calling packetProcess() on them. Well, it ended up that everybody added anything to do with the processing stages (since the manager class was an easy place to access the stages) to this manager class, especially stage configuration. The manager class no longer had a Single Responsibility, but instead was also responsible for making calls to the stages for configuration changes: thus the Cohesion had been reduced.

We ended up having to refactor the manager class, ripping out all the stage configuration and putting it in a factory, thus leaving the manager to do what it was intended to do.

OTHER TIPS

The most effective way to break applications is to create GOD classes. Those are classes that keep track of a lot of information and have several responsibilities. One code change will most likely affect other parts of the class and therefore indirectly all other classes that use it. That in turn leads to an even bigger maintenance mess since no one dares to do any changes other than adding new functionality to it.

The following example is a TypeScript class that defines a Person, this class should not include email validation because that is not related with a person behaviour:

class Person {
    public name : string;
    public surname : string;
    public email : string;
    constructor(name : string, surname : string, email : string){
        this.surname = surname;
        this.name = name;
        if(this.validateEmail(email)) {
          this.email = email;
        }
        else {
            throw new Error("Invalid email!");
        }
    }
    validateEmail(email : string) {
        var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
        return re.test(email);
    }
    greet() {
        alert("Hi!");
    }
}

We can improve the class above by removing the responsibility of email validation from the Person class and creating a new Email class that will have that responsibility:

class Email {
    public email : string;
    constructor(email : string){
        if(this.validateEmail(email)) {
          this.email = email;
        }
        else {
            throw new Error("Invalid email!");
        }        
    }
    validateEmail(email : string) {
        var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
        return re.test(email);
    }
}

class Person {
    public name : string;
    public surname : string;
    public email : Email;
    constructor(name : string, surname : string, email : Email){
        this.email = email;
        this.name = name;
        this.surname = surname;
    }
    greet() {
        alert("Hi!");
    }
}

Making sure that a class has a single responsibility makes it per default also easier to see what it does and how you can extend/improve it.

A class should have only one reason to change.

This principle states that if we have 2 reasons to change for a class, we have to split the functionality in two classes. Each class will handle only one responsibility and if in the future we need to make one change we are going to make it in the class which handles it.

If there are two different reasons to change, it is conceivable that two different teams may work on the same code for two different reasons. Each will have to deploy its solution, which in the case of a compiled language (like C++, C# or Java), may lead to incompatible modules with other teams or other parts of the application.

This principle is closely related to the concepts of coupling and cohesion. Coupling refers to how inextricably linked different aspects of an application are, while cohesion refers to how closely related the contents of a particular class or package may be. All of the contents of a single class are tightly coupled together, since the class itself is a [single unit][1] that must either be entirely used or not at all.

My blog post on this:

http://javaexplorer03.blogspot.in/2016/12/single-responsibility-principle.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top