“This is the 27th day of my participation in the August Genwen Challenge.More challenges in August”

First, what is the responsibility chain model?

In the Chain of Responsibility Pattern, each node in the Chain is regarded as an object, each node handles different requests, and the next node object is automatically maintained internally. When a request is sent from the head of the chain, it is passed along the chain path to each node object until an object processes the request. It belongs to the behavioral pattern.

Multiple objects have the opportunity to process the request, avoiding coupling between the sender and receiver of the request. Connect the objects into a chain and pass the request along the chain until an object processes it.

2. Application scenarios of responsibility chain mode

In daily life, the chain of responsibility mode is still quite common. When we deal with some things in daily work, various departments usually cooperate to complete a certain task. Each department has its own responsibilities, so many times when something is half done, it will be passed on to the next department until it has been reviewed by all departments. There is also a common saying that we usually go through five passes, killing six generals is actually a chain of responsibility.

The responsibility chain mode mainly decouples the request and processing. The customer only needs to send the request to the chain without caring about the specific content and processing details of the request. The request will be transmitted automatically until there is a node object to process it. Applicable to the following application scenarios:

  1. Multiple objects can handle the same request, but which object handles it is dynamically determined at run time.
  2. You can dynamically specify a set of objects to handle requests.

Iii. Roles involved in the chain of responsibility model

Let’s first look at the general UML class diagram of the chain of Responsibility pattern:

From the UML class diagram, we can see that the chain of responsibility pattern mainly contains two roles:

  1. Abstract Handler: Defines a method for processing a request and maintains a reference to a Handler object for the next processing node.
  2. ConcreteHandler: Handles the request and, if not interested, forwards it.

Chain of responsibility pattern is the essence of decoupling requests and processing, make the request can pass and be processed in the processing chain, chain of responsibility pattern should understand its patterns (tao) rather than the specific implementation (art), chain of responsibility pattern is unique is its combination has become the chain structure will be treated as nodes, and allows the node itself to decide whether to request handling or forwarding, It kind of lets the requests flow.

Fourth, use the responsibility chain mode for data verification and interception

First, create an entity class Member:

@Data
public class Member {

    private String loginName;
    private String loginPass;
    private String roleName;

    public Member(String loginName, String loginPass) {
        this.loginName = loginName;
        this.loginPass = loginPass; }}Copy the code

Then take a look at some code we often write:

public class MemberService {

    public void login(String loginName, String loginPass) {
        if (null == loginName || loginName.trim().equals("")) {
            return;
        }
        if (null == loginPass || loginPass.trim().equals("")) {
            return;
        }
        Member member = checkExists(loginName, loginPass);
        if (member == null) {
            System.out.println("User does not exist ~~~);
            return;
        }
        if (!"Administrator".equals(member.getRoleName())) {
            System.out.println("You are not an administrator, do not have operation permission ~");
            return;
        }
        System.out.println("Allowed operation");
    }

    private Member checkExists(String loginName, String loginPass) {
        Member member = new Member(loginName, loginPass);
        member.setRoleName("Administrator");
        return member;
    }

    public static void main(String[] args) {
        MemberService memberService = new MemberService();
        memberService.login("mark"."666888"); }}Copy the code

Do you often do this? In the above code, the main function is to do a pre-login data verification, and then determine the logic is sequential. First make a non-short judgment, then check whether the account is valid, and finally get the user role. Then check whether the user has operation rights based on the rights of the user role. Such verification codes are generally essential, but the code written in the specific business code is very bloated. Therefore, we can use the chain of responsibility mode to connect these inspection steps together without affecting the beauty of the code. It allows us to focus more on a specific business logic processing when coding.

Let’s use the chain of responsibility pattern to optimize the code, first create a Handler class:

public abstract class Handler {

    protected Handler chain;

    public void next(Handler handler) {
        this.chain = handler;
    }

    public abstract void doHandle(Member member);
}
Copy the code

Create a ValidateHandler class for non-null ValidateHandler, a LoginHandler class for login validation, and a AuthHandler class for permission validation.

public class ValidateHandler extends Handler {
    @Override
    public void doHandle(Member member) {
        if (null == member.getLoginName() || member.getLoginName().trim().equals("")) {
            return;
        }
        if (null == member.getLoginPass() || member.getLoginPass().equals("")) {
            return;
        }
        System.out.println("User name and password verification successful, can proceed."); chain.doHandle(member); }}Copy the code

LoginHandler class:

public class LoginHandler extends Handler {
    @Override
    public void doHandle(Member member) {
        System.out.println("Login successful");
        member.setRoleName("Administrator"); chain.doHandle(member); }}Copy the code

AuthHandler class:

public class AuthHandler extends Handler {
    @Override
    public void doHandle(Member member) {
        if (!"Administrator".equals(member.getRoleName())) {
            System.out.println("You are not an administrator, do not have operation permission ~");
            return;
        }
        System.out.println("You are the administrator. Permission to operate."); }}Copy the code

Next, modify the code in MemberService. In fact, we only need to connect the previously defined several handlers according to the business requirements to form a chain.

public class MemberService {

    public void login(String loginName, String loginPass) {
        Handler validateHandler = new ValidateHandler();
        Handler loginHandler = new LoginHandler();
        Handler authHandler = new AuthHandler();

        validateHandler.next(loginHandler);
        loginHandler.next(authHandler);

        validateHandler.doHandle(newMember(loginName, loginPass)); }}Copy the code

Look at the client calling code:

public class Test {

    public static void main(String[] args) {
        MemberService memberService = new MemberService();
        memberService.login("mark"."666888"); }}Copy the code

In fact, we usually use a lot of authority verification framework is the use of such a principle, the authority of each dimension of the understanding of coupling and then series, each only deal with their respective related responsibilities. If the responsibility is not relevant to you, you throw it to the next Handler on the chain.

5. Combination of responsibility chain mode and builder mode

As we can see from the above code, the role responsible for assembling the chain structure is MemberService. When the chain structure is long, the work of MemberService is very tedious, and the MemberService code is relatively bloated, and the handler or message type is changed later, All must be modified in MemberService, which does not match the open and close principle. The reason for these problems is that the assembly of chain structure is too complicated, and for the creation of complex structure, it is natural for us to think of the builder mode. Using the builder mode, we can automatically chain assemble the processing node object specified by MemberService, and the customer only needs to specify the processing node object. Nothing else matters, and the chain structure is constructed differently depending on the order in which the node objects are processed by the customer. Let’s modify the Handler code:

public abstract class Handler<T> {

    protected Handler chain;

    public void next(Handler handler) {
        this.chain = handler;
    }

    public abstract void doHandle(T t);

    public static class Builder<T> {
        private Handler<T> head;
        private Handler<T> tail;

        public Builder<T> addHandler(Handler<T> handler) {
            if (this.head == null) {
                this.head = this.tail = handler;
                return this;
            }
            this.tail.next(handler);
            this.tail = handler;
            return this;
        }

        public Handler<T> build(a) {
            return this.head; }}}Copy the code

Then modify the MemberService code:

public class MemberService {

    public void login(String loginName, String loginPass) {
        Handler.Builder builder = new Handler.Builder();
        builder.addHandler(new ValidateHandler())
                .addHandler(new LoginHandler())
                .addHandler(new AuthHandler());

        builder.build().doHandle(newMember(loginName, loginPass)); }}Copy the code

Since Builder mode builds node handlers, we use Builder as a static inner class of Handler, and since the client does not need to chain assemble, we can also make the chain assembly method next() method private to make Handler more cohesive:

public abstract class Handler<T> {

    protected Handler chain;

    private void next(Handler handler) {
        this.chain = handler;
    }

    public abstract void doHandle(T t);

    public static class Builder<T> {
        private Handler<T> head;
        private Handler<T> tail;

        public Builder<T> addHandler(Handler<T> handler) {
            if (this.head == null) {
                this.head = this.tail = handler;
                return this;
            }
            this.tail.next(handler);
            this.tail = handler;
            return this;
        }

        public Handler<T> build(a) {
            return this.head; }}}Copy the code

Through this case, friends should have felt the essence of the chain of responsibility and the combination of the builder.

Six, responsibility chain model in the source code

First let’s look at the application of the chain of responsibility pattern in the JDK. Let’s look at a very common Filter class in the J2EE standard:

public interface Filter {

    public void init(FilterConfig filterConfig) throws ServletException;

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

    public void destroy(a);
}
Copy the code

The definition of the Filter interface is very simple and corresponds to the Handler abstract role in the chain of responsibilities model, so how does it form a chain of responsibilities? The last argument to the doFilter() method is of type FilterChain.

public interface FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}
Copy the code

The FilterChain class also defines only one doFilter() method, so how do they concatenate into a chain of responsibilities? In fact, J2EE only defines a specification, and the processing logic is implemented by the consumer. Let’s look at a Spring implementation of the MockFilterChain class:

public class MockFilterChain implements FilterChain {
    @Nullable
    private ServletRequest request;
    @Nullable
    private ServletResponse response;
    private final List<Filter> filters;
    @Nullable
    privateIterator<Filter> iterator; .public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        Assert.notNull(request, "Request must not be null");
        Assert.notNull(response, "Response must not be null");
        Assert.state(this.request == null."This FilterChain has already been called!");
        if (this.iterator == null) {
            this.iterator = this.filters.iterator();
        }

        if (this.iterator.hasNext()) {
            Filter nextFilter = (Filter)this.iterator.next();
            nextFilter.doFilter(request, response, this);
        }

        this.request = request;
        this.response = response; }... }Copy the code

It puts all the filters in the chain into the List and then iterates through the List when the doFilter() method is called, meaning that the filters in the List are executed in order.

Seven, the advantages and disadvantages of the responsibility chain model

Advantages:

  1. Decouple requests from locations.
  2. The request handler (node object) only needs to focus on the request that he is interested in processing, for the request that is not interested, directly forward to the next level of node object.
  3. With chain transfer processing request function, request sender need not know the link structure, just wait for the request processing result.
  4. The link structure is flexible, and the responsibilities can be dynamically added or deleted by changing the link structure.
  5. Easy to extend new request processing classes (nodes), in accordance with the open closed principle.

Disadvantages:

  1. If the chain of responsibility is too long or the processing time is too long, the overall performance will be affected.
  2. If a node object has a circular reference, it will cause an infinite loop, causing the system to crash.

8. Friendship links

Design Patterns – Factory Patterns learning tour

Design Patterns – a learning tour of singleton patterns

Design Patterns – A learning journey of prototyping patterns

Design Patterns – Builder patterns learning tour

Design Patterns – Agent patterns learning tour

Design Patterns – A learning tour of facade patterns

Design Patterns – A learning tour of decorator patterns

Design Patterns – Enjoy yuan patterns learning journey

Design Patterns – A learning journey of composite patterns

Design Patterns – Adapter patterns learning journey

Design Patterns – Bridge patterns learning journey

Design Patterns – Delegation patterns learning journey

Design Patterns – a template method pattern learning journey

Design Patterns – A learning journey of Strategic patterns

Welcome to follow the wechat public account (MarkZoe) to learn from and communicate with each other.