责任链设计模式以及在Android中的应用

1,927 阅读7分钟

我们在生活中或者工作中,经常会遇到这样的情况,比如公司报销,一般情况下在提交了报销申请后,先由项目经理审批,然后由财务部门审批,最后由总经理或者更高级别的审批,这种一级一级链式传递的特点,我们可以把它叫做链,又比如在Android开发中,经常能遇到事件的传递,从Activity->ViewGroup->View,这3种级别的传递,当然可以提前进行处理,提前结束流程,Android中的事件传递也一样,可以在传递到ViewGroup的时候就处理掉,类似上面这种情况,在设计模式中叫做责任链设计模式,我们简单讲解一下并且举例在Android中的应用。

简介

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

从定义我们可以知道责任链模式的特点: 1.责任链是对象的行为模式。 2.责任链是一条链,可以是直链或者圆链 3.请求的客户端和最终的处理者没有任何关系,达到解耦的目的。

结构

责任链模式的结构如下:

图是网上找的,大家理解就好,从图中,我们可以看到,责任链有下面几个角色,我们来介绍一下: 1.Handler 是一个抽象的处理者,一般情况下有下一个的处理者和抽象的处理方法,并且有设置下一个处理者的相应方法。这个很重要,是成为链的重要接口方法。 2.ConcreteHandler 是一个具体的处理者,就是在接到具体的请求之后,根据实际情况是处理或者转给下一个处理,一般情况下,如果没有下一个处理者,那么就自己处理。 3.client,客户端是最终发起请求的。

下面我们来看一个具体的简单的场景:

大学中,有时候需要请假,一般情况下,我们假设3天以内的假由班主任审批就好,而3天以上的由辅导员审批即可,我们看一下代码: 首先我们定义一个请假的抽象方法:

/**处理请假抽象
 * Created by Hadoop on 2018/1/5.
 */
public abstract class HandlerLeave {
    protected HandlerLeave mNextHandler=null;

    public HandlerLeave getNextHandler() {
        return mNextHandler;
    }

    /**
     * 设置下一个处理者
     * @param mNextHandler
     */
    public void setNextHandler(HandlerLeave mNextHandler) {
        this.mNextHandler = mNextHandler;
    }

    /**
     * 处理真正的事件
     * @param day
     */
    protected abstract void handRequest(long day);
}

现在我们再定义具体的班主任和辅导员的处理

public class Teacher extends HandlerLeave {
    @Override
    protected void handRequest(long day) {
        if (day < 3) {
            System.out.println("已经处理了学生的请假");
        } else {
            if (getNextHandler() != null) {
                System.out.println("需要给辅导员审批");
                /**
                 * 把请求传递给下一个处理者
                 */
                getNextHandler().handRequest(day);
            }else {
                System.out.printf("如果辅导员不在,则班主任处理就好");
            }
        }
    }
}

我们可以看到当条件不满足时,把请求发给下一个处理者,这句代码很重要,是形成链的关键所在,

public class Instructror extends HandlerLeave {
    @Override
    protected void handRequest(long day) {
        System.out.println("辅导员批准了请假");
    }
}

我们来看看客户端的代码:

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

这里假如请假5天,按道理要给辅导员审批的,我们看下结果:

我们可以看到首先班主任不满足day<3的情况,于是把请求给了辅导员,而辅导员则处理了请假的请求。

责任链模式优缺点

从上面的例子我们可以看到,优点如下:

• 降低耦合度(请求者和处理者可以相互不知道)

• 可简化对象的相互连接,这是形成链的条件

• 增强给对象指派职责的灵活性

• 增加新的请求处理类很方便

而也有一定的缺点,如下:

•不能保证请求一定被接收。能保证的前提是正确设置了下一个环节的处理者,如果没有设置的话,请求到此结束。

•系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。特别是在请求链很长的情况下,一级一级请求,在性能上有影响。

责任链模式在Android中的应用

责任链模式在Android中也发挥了重要的作用,大家所熟知的Android事件分发机制就是责任链模式的经典,不同的是,Android事件分发机制比传统的更加复杂,因为事件的链不仅可以从Activity->ViewGroup->View传递,还可以从View->ViewGroup->Activity传递,形成一个圆环的链,从而逻辑上更加复杂,关于事件分发机制,网上很多文章解析的很详细,我们来看一个实际的例子,当初接手的项目中,登陆以后分为几种用户,分为普通会员,银牌会员,金牌会员,在登陆的时候会触发跳转活动页面,之前的代码就是利用了责任链模式来进行的,当初代码比较复杂,这里简单说下,首先我们也一样定义一个抽象的登陆处理

public abstract 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(int type) {
        this.type = type;
    }

    /**
     * 下一个处理者
     */
    private LoginHandler mNext;
    private int type;

	//分发处理登陆
    public void dispatchLogin(IUserInfo iUserInfo) {
        if (iUserInfo.getUserInfo().getType() == type) {
            dealWithLogin(iUserInfo);
        } else {
            if (getNextLoginHandler() != null) {
                getNextLoginHandler().dispatchLogin(iUserInfo);
            } else {
                Log.d("[app]", "没有符合处理用户的逻辑");
            }
        }
    }

    public LoginHandler getNextLoginHandler() {
        return mNext;
    }

    //设置下一个处理者
    public void setNextHandler(LoginHandler mNext) {
        this.mNext = mNext;
    }

    public abstract void dealWithLogin(IUserInfo user);
}

用户的接口和信息

public interface IUserInfo {
    int getUserType();//用户的级别

    User getUserInfo();//获取用户信息
    //省略一些代码
}

public class UserInfo implements IUserInfo {
    private int type;
    private User user;

	//省略一些代码
    public UserInfo(int type, User user) {
        this.type = type;
        this.user = user;
    }

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

    @Override
    public User getUserInfo() {
        return user;
    }
}

public class User {
    private String name;
    private int age;
    private int uid;
    private String address;
    //会员的类型
    private int type;

    //省略一些代码
    public int getType() {
        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;
    }
}

下面定义3种会员,分别是普通会员,银牌会员和金牌会员的处理逻辑,这里面也简化了,实际上的代码比较复杂

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

    @Override
    public void dealWithLogin(IUserInfo user) {
        Log.d("[app]","处理普通用户的登陆,跳去普通会员活动页面");
        //省略相关操作
    }
}

public class SilveryUserLogin extends LoginHandler{

    public SilveryUserLogin() {
        super(LoginHandler.SILVERY_USER);
    }

    @Override
    public void dealWithLogin(IUserInfo user) {
        Log.d("[app]","处理银牌用户的登陆,跳去银牌会员活动页面");
        //省略相关操作
    }
}

public class GoldUserLogin extends LoginHandler{
    public GoldUserLogin() {
        super(LoginHandler.GOLD_USER);
    }

    @Override
    public void dealWithLogin(IUserInfo user) {
        Log.d("[app]","处理金牌用户的登陆,跳去金牌会员活动页面");
        //省略相关操作
    }
}

OK,我们定义了具体的操作,现在看看登陆以后的事情,代码如下:

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, UserInfo data) {
	                    //省略一些代码
                        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());
                    }
                });
            }
        });

从代码里面可以看出来普通会员的下一级是银牌会员,而银牌会员的下一个处理者是金牌会员,这样一级一级传递下去,最终根据级别找到对应的处理逻辑。实际上个人感觉用策略模式来处理这种逻辑更好,毕竟就3种对应的级别而已,一个接口,3种具体的算法,在后来的重构中,改用了策略模式,关于策略模式,可以参考我的另一篇文章:

策略模式解析以及在Android中的实际应用

今天的文章就写到这里,感谢大家阅读。