In life or work, we often encounter such a situation, such as company submit an expense account, usually after submit the reimbursement application, examination and approval by the project manager first, and then by the financial department for examination and approval, and finally by the general manager or higher level for examination and approval, the characteristics of the primary level of chain transfer, we can call it chain, for instance, in the Android development It is common to encounter event delivery, from Activity->ViewGroup->View, these three levels of delivery, of course, can be processed in advance, end the process in advance, Android event delivery is the same, can be transferred to the ViewGroup when processing, similar to the above situation, The design pattern is called the Chain of Responsibility design pattern, and we’ll briefly explain it and give you an example of how it works in Android.

Introduction to the

Chain of responsibility is an object behavior pattern. In the chain of responsibility pattern, many objects are connected in a chain by each object’s reference to its next parent. Requests pass along the chain until one of the objects on the chain decides to process the request. The client making the request does not know which object on the chain ultimately handles the request, allowing the system to dynamically reorganize and assign responsibilities without affecting the client.

From the definition, we can know the characteristics of the chain of responsibility mode: 1. The chain of responsibility is the behavior mode of the object. 2. Responsibility chain is a chain, which can be straight or round. 3. The client of the request has no relationship with the final handler, so as to achieve the purpose of decoupling.

structure

The structure of the chain of responsibility model is as follows:

A Handler is an abstract Handler, usually with the next Handler and the abstract Handler method, and also with the corresponding method to set the next Handler. This is important, this is an important interface method to be a chain. 2. ConcreteHandler is a concrete handler, is after received a specific request, according to the actual situation is treatment or transferred to the next, in general, if not the next handler, then their processing. 3. Client: The client ultimately initiates the request.

Let’s look at a specific simple scenario:

In the university, sometimes it is necessary to ask for leave. In general, we assume that leave within 3 days will be approved by the head teacher, and leave over 3 days will be approved by the counselor. Let’s have a look at the code: first, we define an abstract method of asking for leave:

/** Created by Hadoop on 2018/1/5. */ public abstract class HandlerLeave {protected HandlerLeave mNextHandler=null; public HandlerLeavegetNextHandler() {
        returnmNextHandler; } /** * Set the next handler * @param mNextHandler */ public voidsetNextHandler(HandlerLeave mNextHandler) { this.mNextHandler = mNextHandler; } @param day */ protected abstract void handRequest(long day); }Copy the code

Now let’s redefine the specific treatment of class teachers and counselors

public class Teacher extends HandlerLeave {
    @Override
    protected void handRequest(long day) {
        if (day < 3) {
            System.out.println("Student leave has been processed.");
        } else {
            if(getNextHandler() ! = null) { System.out.println("It needs to be approved by the counselor."); /** * Pass the request to the next handler */ getNextHandler().handRequest(day); }else {
                System.out.printf("If the counselor is not there, the head teacher will handle it."); }}}}Copy the code

We can see that when the condition is not met, the code that sends the request to the next handler is very important, it’s the key to the chain,

public class Instructror extends HandlerLeave {
    @Override
    protected void handRequest(long day) {
        System.out.println("The counselor approved the leave."); }}Copy the code

Let’s look at the client code:

public class Client { public static void main(String[] args){ HandlerLeave handlerLeave=new Teacher(); HandlerLeave handlerLeave1=new Instructror(); handlerLeave.setNextHandler(handlerLeave1); handlerLeave.handRequest(5); }}Copy the code

If ask for leave 5 days here, should give counsellor examine and approve by reason, we look next result:

We can see that the head teacher does not meet the requirement of day<3, so he sends the request to the counselor, and the counselor deals with the request for leave.

Advantages and disadvantages of the chain of responsibility model

As we can see from the above example, the advantages are as follows:

• Reduce coupling (requester and handler can be unaware of each other)

• Simplifies the interconnecting of objects, which is the condition for forming chains

• Increased flexibility in assigning responsibilities to objects

• Adding new request handling classes is convenient

But also has certain disadvantages, as follows:

• There is no guarantee that the request will be received. The only guarantee is that the handler for the next segment is set correctly. If not, the request ends.

• System performance will be affected, and it is not convenient for code debugging; It may cause a circular call. Especially in the case of long request chains, level by level requests have an impact on performance.

The application of Responsibility chain mode in Android

The responsibility chain mode also plays an important role in Android. The well-known Android event distribution mechanism is the classic responsibility chain mode. The difference is that the Android event distribution mechanism is more complex than the traditional one, because the chain of events can not only be transmitted from Activity->ViewGroup->View, As for the event distribution mechanism, many articles on the Internet are very detailed. Let’s take a look at a practical example. In the project I took over at the beginning, there were several users after logging in, including ordinary members and silver members. Gold member, when logging in will trigger the jump to the activity page, the previous code is the use of the chain of responsibility mode to carry out, the original code is more complex, here simply, first of all, we also define an abstract login processing

Public final static int NORMAL_USER = 1; public class LoginHandler {public final static int NORMAL_USER = 1; public final static int SILVERY_USER = 2; public final static int GOLD_USER = 3; public LoginHandler(inttype) {
        this.type = type; } /** * private LoginHandler mNext; private inttype; Public void dispatchLogin(IUserInfo IUserInfo) {if (iUserInfo.getUserInfo().getType() == type) {
            dealWithLogin(iUserInfo);
        } else {
            if(getNextLoginHandler() ! = null) { getNextLoginHandler().dispatchLogin(iUserInfo); }else {
                Log.d("[app]"."There is no logic for dealing with users.");
            }
        }
    }

    public LoginHandler getNextLoginHandler() {
        returnmNext; } // Set the next handler to public voidsetNextHandler(LoginHandler mNext) {
        this.mNext = mNext;
    }

    public abstract void dealWithLogin(IUserInfo user);
}
Copy the code

User interface and information

public interface IUserInfo { int getUserType(); // User level User getUserInfo(); } public class UserInfo implements IUserInfo {private inttype; private User user; // omit some code public UserInfo(inttype, User user) {
        this.type = type;
        this.user = user;
    }

    @Override
    public int getUserType() {
        return type;
    }

    @Override
    public User getUserInfo() {
        returnuser; } } public class User { private String name; private int age; private int uid; private String address; // Member type private inttype; // omit some code public intgetType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) { this.address = address; }}Copy the code

The following three types of members are defined, which are the processing logic of ordinary member, silver member and gold member respectively, which is also simplified, and the actual code is complicated

public class NormalUserLogin extends LoginHandler{
    public NormalUserLogin() {
        super(LoginHandler.NORMAL_USER);
    }

    @Override
    public void dealWithLogin(IUserInfo user) {
        Log.d("[app]"."Handle regular user login, skip to regular member activity page."); }} public class SilveryUserLogin extends LoginHandler{publicSilveryUserLogin() {
        super(LoginHandler.SILVERY_USER);
    }

    @Override
    public void dealWithLogin(IUserInfo user) {
        Log.d("[app]"."Handle silver user login, go to silver member activity page"); }} public class GoldUserLogin extends LoginHandler{publicGoldUserLogin() {
        super(LoginHandler.GOLD_USER);
    }

    @Override
    public void dealWithLogin(IUserInfo user) {
        Log.d("[app]"."Handle gold user login, jump to gold member activity page"); // omit related operations}}Copy the code

OK, we have defined the specific operation, now look at the login after the event, the code is as follows:

textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LoginBiz.userLogin(data, new BizCallback<UserInfo>() { @Override public void onSuccess(int code, String message, LoginHandler Handler1 =new NormalUserLogin(); LoginHandler handler2=new SilveryUserLogin(); LoginHandler handler3=new GoldUserLogin(); handler1.setNextHandler(handler2); handler2.setNextHandler(handler3); handler1.dispatchLogin(data); } @Override public void onFail(Throwable throwable) { ProgressDialogUtil.dismiss(); toast(throwable.getMessage()); }}); }});Copy the code

It can be seen from the code that the next level of the ordinary member is the silver member, and the next level of the silver member is the gold member. In this way, the processing logic is finally found according to the level. In fact, I think it is better to use the strategic mode to deal with this logic. After all, there are only three corresponding levels, one interface and three specific algorithms. In the later reconstruction, the strategic mode was used.

Strategy pattern analysis and practical application in Android

That’s all for today’s article. Thank you for reading it.