Design Principle - Single Responsibility Principle

Single Responsibility Principle: Each class is only responsible for its own things, rather than becoming omnipotent.

meaning

  • Single responsibility ( Simple Responsibility Pinciple, SRP) means that there should not be more than one reason for a class change
  • A class is only responsible for one responsibility, there should be only one reason for its change, and the responsibility is completely encapsulated in a class

advantage

  • It can reduce the complexity of the class. A class is only responsible for one responsibility, and its logic is definitely much simpler than responsible for multiple responsibilities.
  • Improve the readability of classes and improve the maintainability of the system
  • Risks caused by changes are reduced. Changes are inevitable. If the single responsibility principle is followed well, when one function is modified, the impact on other functions can be significantly reduced.

Method to realize

The single responsibility principle is the simplest but most difficult principle to apply. It requires designers to discover the different responsibilities of a class, separate them, and then encapsulate them into different classes or modules. However, discovering multiple responsibilities of a class requires designers to have strong skills. Analysis and design capabilities, understanding of business and relevant refactoring experience

question

For example, a class T is responsible for two different responsibilities: responsibility P1 and responsibility P2.

When class T needs to be modified due to changes in the requirements of responsibility P1, it may cause the function of responsibility P2 that was originally running normally to malfunction.

Solution

Follow the single responsibility principle. Create two classes T1 and T2 respectively, so that T1 can complete the function of responsibility P1, and T2 can complete the function of responsibility P2.

In this way, when class T1 is modified, responsibility P2 will not be at risk of failure; similarly, when T2 is modified, responsibility P1 will not be at risk of failure.

Expand

Speaking of the Single Responsibility Principle, many people are actually using it without knowing it. Even people who have not studied design patterns or have never heard of the concept of the Single Responsibility Principle will consciously abide by this important principle because it is a Common sense, for example, when you develop a new business function on an original project, you will definitely create a new class to implement a new function, and you will definitely not directly write business B based on the original A function. Function, I will definitely write a new class to implement function B. In software programming, no one wants to cause other functions to malfunction by modifying one function. 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 programs written by experienced programmers will have code that violates this principle. Why would such phenomenon happen? Because there is a proliferation of responsibilities. The so-called responsibility diffusion means that for some reason, responsibility P is divided into finer-grained responsibilities P1 and P2.

For example: Class T is only responsible for one responsibility P, so the design complies with the single responsibility principle. Later, for some reason, maybe the requirements changed, maybe the program designer's level improved, and the responsibility P needed to be subdivided into finer-grained responsibilities P1 and P2. At this time, if you want the program to follow the single responsibility principle, you need to Class T is also decomposed into two classes T1 and T2, which are responsible for the two responsibilities of P1 and P2 respectively. But when the program has already been written, this is simply too time-consuming. Therefore, it is a good choice to simply modify class T and use it to be responsible for two responsibilities, although this goes against the single responsibility principle. (The risk of doing this lies in the uncertainty of responsibility diffusion, because we will not think that this responsibility P may spread to P1, P2, P3, P4...Pn in the future. So remember, when the responsibility spreads to the point where we have no control Refactor the code immediately before reaching the level. )

for example

class level

/**
 * 调用类
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Course course = new Course();
        course.liveCourse("直播课");
        course.liveCourseEncrypt("直播课");
        course.ReplayCourse("录播课");
        course.ReplayCourseEncrypt("录播课");
    }
}
/**
 * 课程类
 */
public class Course {
    
    
    public void liveCourse(String courseName) {
    
    
        System.out.println(courseName + ":不能快进");
    }

    public void liveCourseEncrypt(String encryptType) {
    
    
        System.out.println("加密方式A" + encryptType);
    }

    public void ReplayCourse(String courseName) {
    
    
        System.out.println(courseName + ":可以任意的来回播放");
    }

    public void ReplayCourseEncrypt(String encryptType) {
    
    
        System.out.println("加密方式B" + encryptType);
    }
}

The Course class is responsible for two types of processing logic. If you want to encrypt the course now, then the live class and the recorded class will be encrypted, but the encryption method is different, so there will be
multiple reasons for the course class to change (the class is modified) (live class or recorded class) ,
Since there are multiple reasons, we need to ,separate and decouple responsibilities into live class classes and ,recorded class classes.

LiveCourse

/**
 * 直播课
 */
public class LiveCourse {
    
    
    public void watch(String courseName) {
    
    
        System.out.println(courseName + ":不能快进");
    }

    public void encrypt(String encryptType) {
    
    
        System.out.println("加密方式A" + encryptType);
    }
}

ReplayCourse

/**
 * 录播课
 */
public class ReplayCourse {
    
    
    public void watch(String courseName) {
    
    
        System.out.println(courseName + ":可以任意的来回播放");
    }

    public void encrypt(String encryptType) {
    
    
        System.out.println("加密方式B" + encryptType);
    }
}
/**
 * 课程
 */
public class Course {
    
    
    public static void main(String[] args) {
    
    
        LiveCourse liveCourse = new LiveCourse();
        liveCourse.watch("直播课");
        ReplayCourse replayCourse = new ReplayCourse();
        replayCourse.watch("录播课");
    }
}

If you add offline courses in the future, you can continue to add a new OfflineCourse class for expansion; divide it according to different businesses and use it as our guideline to achieve high cohesion and low coupling.

Interface level

The business continues to develop, and the courses must be authorized. Students who have not paid can obtain the basic information permission of the course, and students who have paid can obtain the learning permission. Then there are at least two responsibilities at the control course level. We can separate presentation responsibilities and management responsibilities and both implement the same abstract dependency.

Design a top-level interface

public interface ICourse {
    
    
    //获得基本信息
    String getCourseName();

    //获得视频流
    byte[] getCourseVideo();

    //更新课程
    void updateCourse();

    //删除课程
    void deleteCourse();
}

By learning the single responsibility at the class level, we can split this interface into two interface classes and create an interface for ordinary users (ICourseInfo) and administrator (ICourseManager)

/**
 * 展示
 */
public interface ICourseInfo {
    
    
    //获得基本信息
    String getCourseName();

    //获得视频流
    byte[] getCourseVideo();
}
/**
 * 管理
 */
public interface ICourseManager {
    
    
    //更新课程
    void updateCourse();

    //删除课程
    void deleteCourse();
}

method level

public class AddMsg {
    
    
    private void add(String userName, String address, String[] addOther) {
    
    
        //添加用户信息
        userName = "张三";
        address = "常州";
        //添加其他无关信息
        addOther = new String[123];
    }
}

The above add() method assumes multiple responsibilities. It can modify user information and other miscellaneous data, which obviously does not meet the single responsibility. Then we make the following modifications and split this method into two:

public class AddMsg {
    
    
    private void addUser(String userName, String address) {
    
    
        //添加用户信息
        userName = "XiaoQiang";
        address = "Changsha";
    }

    private void addOther(String[] addOther) {
    
    
        //添加其他无关信息
        addOther = new String[123];
    }
}

After this modification, it is simple to develop and easy to maintain. Therefore, in the process of writing code, try to keep the interfaces and methods with a single responsibility as much as possible to facilitate the later maintenance of our project.

Each of these three methods has its advantages and disadvantages, so which one should be used in actual programming? In fact, this is really difficult to say and needs to be determined based on the actual situation. My principle is: Only when the logic is simple enough can the single responsibility principle be violated at the code level; only when the number of methods in a class is small enough can the single responsibility principle be violated at the method level;

For example, the example cited in this article is too simple, so whether it is a violation of the single responsibility principle at the code level or a violation at the method level, it will not have much impact. Classes in actual applications are much more complex. Once responsibility diffusion occurs and a class needs to be modified, unless the class itself is very simple, it is better to follow the single responsibility principle.

Guess you like

Origin blog.csdn.net/qq_42700109/article/details/132861191