Design Patterns - SRP of Six Design Principles (Single Responsibility)

overview

The Single Responsibility Principle (SRP), also known as the single function principle, is one of the five basic principles of object-oriented (SOLID). It states that a class should have only one reason to change.

In the world of programming, SOLID is a mnemonic acronym introduced by Robert C. Martin in the early 2000s to refer to the five basic principles of object-oriented programming and object-oriented design. When applied together, these principles make it possible for a programmer to develop a system that is easy to maintain and extend.

SOLID is an acronym for the following five words:

Single Responsibility Principle (Single Responsibility Principle)

Open Closed Principle
Liskov Substitution Principle
Interface Segregation Principle (interface isolation principle)
Dependency Inversion Principle (Dependency Inversion Principle)

Let's imagine: Adding the functional requirements that need to be developed is not one-time, and it will continue to change with the development of the business. Then when a Class class is responsible for more than two or more functions, it will continue to iterate the requirements and implement the class. In the case of continuous expansion, many problems will arise over time, such as difficult code maintenance, difficult expansion, difficult testing, and high online risk.

The so-called responsibility refers to the reason for the class change, that is, the business requirement. If a class has more than one reason to be changed, then the class has more than two responsibilities. And single direct is the reason for agreeing that a class should have one and only one change.

Case

  • Guest user, xxxx
  • regular member, xxxx
  • VIP member, xxxx

Bad Impl

public class VideoUserService {

    public void serveGrade(String userType){
        if ("VIP user".equals(userType)){
            System.out.println("VIP user, video 1080 P blu ray");
        } else if ("general user".equals(userType)){
            System.out.println("Ordinary users, video 720 P Ultra-clear");
        } else if ("guest user".equals(userType)){
            System.out.println("Guest user, video 480 P hd");
        }
    }

}

It can be seen that the implementation is very simple, and there will be no problems for the time being. But this class contains multiple different behaviors, that is, multiple user responsibilities. If you perform function extension or logic modification on such a class, it will appear very bloated.

Next, let's see how to call processing and write a single test

    @Test
    public void test_serveGrade(){
        VideoUserService service = new VideoUserService();
        service.serveGrade("VIP user");
        service.serveGrade("general user");
        service.serveGrade("guest user");
    }

Because the above implementation method is the business logic implemented by if else in VideoUserService#serveGrade, so when calling the method, all responsible users use a method to implement it as the call entry of the program.

There is nothing wrong with simple requirements. Code modifications brought about by frequently changing requirements may affect other logic and bring uncontrollable risks to the entire interface service.

Better Impl

In order to meet the needs of continuous iteration, it is not possible to use one class to confuse all responsibility behaviors, but to provide an upper-level interface, provide separate implementation classes for different differentiated users, and split their respective responsibility boundaries.

1. Define the interface

public interface IVideoUserService {

    // Video clarity level; 480P, 720P, 1080P
    void definition();

    // How to play ads; no ads, ads
    void advertisement();

}

Define the upper layer interface IVideoUserService, and uniformly define the functions that need to be implemented: video clarity level interface, advertisement playback mode interface. Three different types of users can implement their own service classes respectively to achieve unified responsibilities.

2. Separation of duties - multiple implementation classes

[Visit customers]

public class GuestVideoUserService implements IVideoUserService {
    
    public void definition() {
        System.out.println("Guest user, video 480 P hd");
    }

    public void advertisement() {
        System.out.println("Guest user, video with ads");
    }

}

[Ordinary member]

public class OrdinaryVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("Ordinary users, video 720 P Ultra-clear");
    }

    public void advertisement() {
        System.out.println("Ordinary users, videos with ads");
    }

}

[VIP]

public class VipVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("VIP user, video 1080 P blu ray");
    }

    public void advertisement() {
        System.out.println("VIP user, video without ads");
    }

}

To sum up, the service responsibilities corresponding to each user have their own classes responsible for implementation without interfering with each other. When a certain category needs to add new operating rules, the operation is relatively simple.

3. Unit testing

  @Test
    public void test_VideoUserService(){

        IVideoUserService guest = new GuestVideoUserService();
        guest.definition();
        guest.advertisement();

        IVideoUserService ordinary = new OrdinaryVideoUserService();
        ordinary.definition();
        ordinary.advertisement();

        IVideoUserService vip = new VipVideoUserService();
        vip.definition();
        vip.advertisement();

    }

It can be seen that after optimizing with a single principle, each class is only responsible for its own user behavior. Subsequent expansion or modification only needs to modify a certain user behavior class.

summary

In the project development, try to ensure that the definition of the interface, the implementation of the class, and the development of the method maintain a single responsibility, which is very helpful for the iteration and maintenance of the project.

Tags: Java Design Pattern

Posted by pakmannen on Tue, 24 Jan 2023 02:18:07 +0300