Definition: Do not have more than one cause of a class change. In layman’s terms, a class has only one responsibility.

Class T is responsible for two different responsibilities: responsibility P1 and responsibility P2. When class T needs to be modified due to a change in the requirements of responsibility P1, it is possible that the function of responsibility P2, which is normally functioning, will fail.

The solution: Follow the single responsibility principle. Establish two classes T1 and T2 respectively, so that T1 completes the function of responsibility P1 and T2 completes the function of responsibility P2. This way, when class T1 is modified, responsibility P2 is not at risk of failure; Similarly, when T2 is modified, there is no risk of failure in responsibility P1.

Many people dismiss the single responsibility principle. Because it’s so easy. Even experienced programmers who have never read design patterns or heard of the single responsibility principle will consciously follow this important principle when designing software because it is common sense. In software programming, you don’t want to change one function so that something else breaks down. The way to avoid this problem is to follow the single responsibility principle. Although the single responsibility principle is so simple and considered common sense, even experienced programmers write programs that violate it. Why does this happen? Because there is diffusion of responsibility. Responsibility diffusion is when responsibility P is, for some reason, divided into more granular responsibilities P1 and P2.

For example, class T is responsible for only one responsibility, P, which is consistent with the single responsibility principle. Later, due to some reasons, maybe the requirements changed or the designer realm of the program improved, it was necessary to subdivide responsibility P into finer responsibilities P1 and P2. At this time, to make the program follow the principle of single responsibility, it was necessary to divide class T into two classes T1 and T2, responsible for two responsibilities P1 and P2 respectively. But when the program is already written, it takes too long to do so. So, it’s a good idea to simply modify class T to take care of both responsibilities, even if that violates the single responsibility principle. (The risk of this is the uncertainty of responsibility diffusion, because we don’t think of responsibility P, which in the future may spread to P1, P2, P3, P4… The Pn. So remember to refactor the code before responsibility spreads beyond our control.)

For example, use a class to describe the animal breathing situation:

1 class Animal{2 public void breathe(String Animal){3 system.out.println (Animal +" breathe "); 4 } 5 } 6 public class Client{ 7 public static void main(String[] args){ 8 Animal animal = new Animal(); 9 animal. Breathe (" cow "); 10 animal. Breathe (" sheep "); 11 animal. Breathe (" pig "); 13 12}}Copy the code

Running results:

Cows breathe air sheep breathe air pigs breathe air

After the program went online, I found the problem, not all animals breathe air, for example, fish is breathing water. If you follow the single responsibility principle when modifying, you need to subdivide Animal class into Terrestrial, Aquatic Aquatic, code as follows:

1 class Terrestrial{2 public void breathe(String animal){3 system.out.println (animal+" breathe air "); 4} 5} 6 class Aquatic{7 public void breathe(String animal){8 system.out.println (animal+" breathe water "); 9 } 10 } 11 12 public class Client{ 13 public static void main(String[] args){ 14 Terrestrial terrestrial = new Terrestrial(); 15 terrestrial. Breathe (" cow "); 16 terrestrial. Breathe (" sheep "); 17 terrestrial. Breathe (" pig "); 18 Aquatic aquatic = new Aquatic(); 19 aquatic. Breathe (" fish "); 20}} 21Copy the code

Running results:

Cows breathe air sheep breathe air pigs breathe air fish breathe water

We will find that if this modification is expensive, we will need to change the client in addition to the original class decomposition. Modifying class Animal to do this violates the single responsibility principle, but costs a lot less.

1 class Animal{2 public void breathe(String Animal){3 if(" fish ".equals(Animal)){4 system.out.println (Animal +" breathe water "); 5}else{6 system.out.println (animal+" breathe air "); 7 } 8 } 9 } 10 11 public class Client{ 12 public static void main(String[] args){ 13 Animal animal = new Animal(); 14 animal. Breathe (" cow "); 15 animal. Breathe (" sheep "); 16 animal. Breathe (" pig "); 17 animal. Breathe (" fish "); 18}} 19Copy the code

As you can see, this is much simpler. But there is a hidden danger: one day need to put the fish into respiration freshwater fish and sea fish, are need to modify the breathe of Animal class methods, and to modify the original code to call the “pig” “cow” “sheep” related functions such as risk, maybe one day you will find that the result of the program is running into a “cow water breathing”. This approach directly violates the single responsibility principle at the code level, which is the easiest to change, but the most dangerous. There is another way to modify:

1 class Animal{2 public void breathe(String Animal){3 system.out.println (Animal +" breathe "); 4} 6 public void breathe2(String animal){7 system.out.println (String animal+" breathe2 "); 8 } 9 } 10 11 public class Client{ 12 public static void main(String[] args){ 13 Animal animal = new Animal(); 14 animal. Breathe (" cow "); 15 animal. Breathe (" sheep "); 16 animal. Breathe (" pig "); 17 animal. Breathe2 (" fish "); 18}} 19Copy the code

As you can see, this modification does not change the original method, but adds a new method to the class, which also violates the single responsibility rule, but is consistent with the single responsibility rule at the method level because it does not change the original method code. Each of these three approaches has its advantages and disadvantages, so in the actual programming, which one to use? It’s really hard to say, it depends on the situation. My rule is that you should only violate the single responsibility principle at the code level if the logic is simple; Only a sufficiently small number of methods in a class can violate the single responsibility principle at the method level;

The example in this article, for example, is so simple that it has only one method, so violating the single responsibility principle at either the code level or the method level doesn’t matter much. In practice, classes are much more complex. When responsibility proliferation occurs and you need to modify a class, it is better to follow the single responsibility principle unless the class itself is very simple.

The advantages of following a single responsibility are:

  • You can reduce the complexity of a class, a class is responsible for only one responsibility, its logic is certainly much simpler than responsible for multiple responsibilities;
  • Improve class readability and system maintainability;
  • The risk reduction caused by change is inevitable, and if the single responsibility principle is followed well, when modifying one function, the impact on other functions can be significantly reduced.

It is important to note that the single responsibility principle is not unique to object-oriented programming but applies to modular programming.