There is no road in life in vain. Every step counts
preface
In object-oriented software design, only reduce the coupling degree between modules as far as possible, can improve the code reuse rate, system maintainability, scalability can be improved. Object-oriented software design, there are 23 kinds of classical design patterns, is a set of previous code design experience summary, if the design pattern is compared to martial arts moves, then the design principle is like internal work mind method. There are seven commonly used design principles, this article will specifically introduce the single responsibility principle.
Introduction to Design Principles
- Single responsibility principle: focus on reducing the complexity of the class, implement the class to have a single responsibility;
- The open close principle: The core of all object-oriented principles, design is closed to extension development and modification;
- In substitution principle: one of the important ways to realize the open and close principle, the design should not destroy the inheritance relationship;
- Dependency inversion principle: the concrete implementation of system abstraction requires interface oriented programming, which is one of the main implementation mechanisms of object-oriented design.
- Interface isolation principle: Interface methods should be as few as possible and interfaces should be as detailed as possible.
- Demeter’s law: reduce the coupling degree of the system, so that the modification of one module will affect other modules as little as possible, and the expansion will be relatively easy;
- Principle of combinatorial reuse: in software design, try to use combinatorial/aggregation rather than inheritance to achieve code reuse.
These design principles do not mean that we must follow them to design, but according to our actual situation to choose how to use them, to make our program do more perfect.
Single responsibility principle
There should be only one reason for a class to change. In layman’s terms, a class has only one responsibility. At the heart of this principle is decoupling and enhanced cohesion.
If a class takes on too many responsibilities, these responsibilities are coupled together, and changes in one responsibility may impair or inhibit the class’s ability to perform other responsibilities. This coupling can lead to fragile designs.
Advantages:
(1) Reduce the class complexity;
(2) Improve the readability of the class and the maintainability of the system;
(3) Reduce the risk caused by changes (reduce the impact on other functions).
Let’s use some simple examples to illustrate the single responsibility principle
public class Animal {
public void breathe(String animal) {
System.out.println(animal + "Lives on land."); }}public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
animal.breathe("Cow");
animal.breathe("Sheep"); }}Copy the code
Running results:
Cattle live on land sheep live on landCopy the code
Not all animals live on Land, but fish live in Water. If the modification follows the principle of single responsibility, it needs to subdivide Animal into Land Animal and Water Animal, and the code is as follows:
public class Land {
public void breathe(String animal) {
System.out.println(animal + "Lives on land."); }}public class Water {
public void breathe(String animal) {
System.out.println(animal + "Living in the water."); }}public class Test {
public static void main(String[] args) {
Land land = new Land();
land.breathe("Cow");
land.breathe("Horse");
Water water = new Water();
water.breathe("Fish"); }}Copy the code
Running results:
Cows live on land horses live on land fish live in waterCopy the code
But the problem is that if this modification is expensive, in addition to decomposing the original class, you also need to modify the client. Modifying class Animal to do this violates the single responsibility principle, but costs a lot less.
public class Animal {
public void breathe(String animal) {
if ("Fish".equals(animal)) {
System.out.println(animal + "Living in the water.");
}
System.out.println(animal + "Lives on land."); }}public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
animal.breathe("Cow");
animal.breathe("Sheep");
animal.breathe("Fish"); }}Copy the code
Running results:
Cows live on land horses live on land fish live in waterCopy the code
As you can see, this is much simpler. However, there is a danger: one day the fish need to be divided into fresh water fish and sea fish, the Animal class needs to change its breathe method, and the modification of the original code will bring the risk of calling “pig”, “cow”, “sheep” and other functions.
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:
public class Animal {
public void breathe(String animal) {
System.out.println(animal + "Lives on land.");
}
public void breathe1(String animal) {
System.out.println(animal + "Living in the water."); }}public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
animal.breathe("Cow");
animal.breathe("Sheep");
animal.breathe1("Fish"); }}Copy the code
Running results:
Cows live on land horses live on land fish live in waterCopy 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.
conclusion
The above application scenario briefly introduces the use of the single responsibility principle. The above three designs are not the most reasonable, but the most appropriate.
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.
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 most important thing to understand about the single responsibility principle is to understand the division of responsibilities, the granularity of which depends on the granularity of the requirements.