23种设计模式-责任链模式(Android开发实际应用场景介绍)

什么是责任链模式

责任链模式是一种行为型设计模式,它的核心思想是将请求从一系列处理者中传递,直到其中一个处理者能够处理它为止。在这个过程中,请求可以被任何一个处理者处理,也可以被拒绝,直到有一个处理者能够处理请求。

在Java开发中,责任链模式的实现方式通常是通过一个抽象处理者(Handler)类来定义处理者的接口,并在这个类中定义一个指向下一个处理者的引用,形成一个链式结构。具体处理者(Concrete Handler)则继承自抽象处理者,并实现其处理请求的方法。当一个请求被发起时,它会首先被传递到第一个处理者,如果第一个处理者不能处理它,那么请求会被传递到下一个处理者,直到有一个处理者能够处理它为止。

责任链模式代码解释

下面我们以一个简单的例子来说明责任链模式的使用方法。假设我们有一个请假系统,需要根据不同的请假天数来分别由部门经理、人事主管和总经理进行审核。如果请假天数不超过2天,由部门经理审核;如果请假天数不超过5天,由人事主管审核;如果请假天数超过5天,则需要总经理审核。

首先我们定义一个抽象处理者类Handler:

public abstract class Handler {
    protected Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handleRequest(int days);
}

在这个类中,我们定义了一个指向下一个处理者的引用successor,并提供了一个设置下一个处理者的方法setSuccessor。同时,我们还定义了一个抽象方法handleRequest,该方法用于处理请求。具体的处理者将继承这个类,并实现自己的handleRequest方法。

下面我们来定义具体的处理者类。首先是部门经理处理者:

public class DepartmentManager extends Handler {
    @Override
    public void handleRequest(int days) {
        if (days <= 2) {
            System.out.println("部门经理审批通过");
        } else {
            if (successor != null) {
                successor.handleRequest(days);
            }
        }
    }
}

在这个类中,我们实现了父类中定义的handleRequest方法,如果请假天数不超过2天,则部门经理能够处理该请求并输出相应的处理结果;否则,请求将被传递给下一个处理者,即人事主管处理者。

接下来是人事主管处理者:

public class HRManager extends Handler {
    @Override
    public void handleRequest(int days) {
        if (days <= 5) {
            System.out.println("人事主管审批通过");
        } else {
            if (successor != null) {
                successor.handleRequest(days);
            }
        }
    }
}

这个类的实现与部门经理处理者类类似,如果请假天数不超过5天,则人事主管能够处理该请求并输出相应的处理结果;否则,请求将被传递给下一个处理者,即总经理处理者。

最后是总经理处理者:

public class GeneralManager extends Handler {
    @Override
    public void handleRequest(int days) {
        System.out.println("总经理审批通过");
    }
}

这个类的实现非常简单,因为总经理是责任链中的最后一个处理者,无论请求的请假天数是多少,总经理都能够处理该请求。

最后我们来测试一下这个责任链模式的实现:

public class Test {
    public static void main(String[] args) {
        Handler departmentManager = new DepartmentManager();
        Handler hrManager = new HRManager();
        Handler generalManager = new GeneralManager();

        departmentManager.setSuccessor(hrManager);
        hrManager.setSuccessor(generalManager);

        departmentManager.handleRequest(1);
        departmentManager.handleRequest(3);
        departmentManager.handleRequest(7);
    }
}

在这个测试程序中,我们首先创建了部门经理、人事主管和总经理三个处理者,然后通过setSuccessor方法将它们组合成一个责任链。最后我们分别测试了请求请假1天、请假3天和请假7天的情况。运行结果如下:

部门经理审批通过
人事主管审批通过
总经理审批通过

可以看到,在请求请假1天、请假3天和请假7天的情况下,责任链分别被部门经理、人事主管和总经理处理,并输出了相应的处理结果。

Android开发中的实际应用解析

在安卓中,责任链模式也有广泛的应用。例如,Android中的事件分发机制就是一种典型的责任链模式。当用户触摸屏幕时,事件首先会被传递给Activity,在Activity中处理完后,事件会继续被传递给它的子View,由子View来处理。如果子View不能处理该事件,事件会被传递给父View,直到事件被处理为止。这个过程形成了一个责任链,而每个View都是责任链中的一个处理者。下面我们来看一下Android源码中的事件分发机制实现。

Android中的事件分发机制是从ViewGroup类开始的。ViewGroup类继承自View类,是一种特殊的View,可以包含其他View。在ViewGroup类中,有一个onInterceptTouchEvent方法,用于拦截子View的触摸事件。如果一个ViewGroup在onInterceptTouchEvent方法中返回了true,则表示它要拦截子View的触摸事件,并将事件交给自己的onTouchEvent方法来处理。如果返回了false,则表示它不拦截子View的触摸事件,将事件传递给子View来处理。

下面是ViewGroup类中onInterceptTouchEvent方法的源码:

public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
            && ev.getActionMasked() == MotionEvent.ACTION_DOWN
            && ev.isButtonPressed(MotionEvent.BUTTON_SECONDARY)) {
        // The right mouse button is currently pressed.
        // We want to give the user a chance to reconsider before
        // performing an action that cannot be undone, such as dismissing
        // a notification or deleting a message.
        showContextMenu();
        return true;
    }

    if (mOnInterceptTouchListener != null && mOnInterceptTouchListener.onTouch(this, ev)) {
        return true;
    }

    if (ev.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        final int action = ev.getAction();
        final float x = ev.getX();
        final float y = ev.getY();

        if (action == MotionEvent.ACTION_DOWN) {
            mLastTouchDownIndex = ev.getActionIndex();
            mLastTouchDownTime = ev.getDownTime();
            mLastTouchDownX = x;
            mLastTouchDownY = y;
            mIgnoreNextUpEvent = false;
        } else {
            // Short circuit if we've already canceled, or if we have no
            // children.
            final boolean canceled = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!canceled && mChildrenCount != 0) {
                // If this is a pointer event, propagate it to our children.
                if (action == MotionEvent.ACTION_POINTER_DOWN
                        || action == MotionEvent.ACTION_MOVE) {
                    final int index = ev.getActionIndex();
                    final int id = ev.getPointerId(index);
                    if (id != mScrollPointerId) {
                        final float dx = x - mLastTouchDownX;
                        final float dy = y - mLastTouchDownY;
                        final float xDiff = Math.abs(dx);
                        final float yDiff = Math.abs(dy);
                        final int touchSlop = mTouchSlop;
                        final boolean isGeneratedGesture = ev.isGeneratedGesture();
                        boolean interceptHorizontal = false;
                        boolean interceptVertical = false;
                        if ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) == 0) {
                            if ((mNestedScrollAxes & SCROLL_AXIS_HORIZONTAL) != 0) {
                                interceptHorizontal |= (xDiff > touchSlop);
                            }
                            if ((mNestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0) {
                                interceptVertical |= (yDiff > touchSlop);
                            }
                        }

                        if (isGeneratedGesture
                                || interceptHorizontal
                                || interceptVertical
                                || hasPointersOutOfView()) {
                            mLastTouchMotionY = y;
                            mLastTouchMotionX = x;
                            cancelAndClearTouchTargets(ev);
                            return true;
                        }
                    }
                } else if (action == MotionEvent.ACTION_POINTER_UP) {
                    final int index = ev.getActionIndex();
                    final int id = ev.getPointerId(index);
                    if (id == mScrollPointerId) {
                        // This was our active pointer going up. Choose a new
                        // action pointer and adjust accordingly.
                        final int newIndex = ev.getPointerCount() - 1;
                        mLastTouchDownX = ev.getX(newIndex);
                        mLastTouchDownY = ev.getY(newIndex);
                        mLastTouchDownIndex = ev.findPointerIndex(newIndex);
                        if (mVelocityTracker != null) {
                            mVelocityTracker.clear();
                        }
                    }
                }
            }
        }
    }

    return false;
}

可以看到,在onInterceptTouchEvent方法中,首先判断了是否有设置OnInterceptTouchListener,如果有则交由OnInterceptTouchListener来处理触摸事件。

接着,如果触摸事件是鼠标右键的按下事件,则弹出上下文菜单并返回true,拦截触摸事件,防止后续的触摸事件继续传递下去。

如果以上两种情况都不满足,则判断触摸事件是否来自于指针,如果是,则根据具体的触摸事件类型进行处理。例如,如果是按下事件,则记录下按下的坐标和时间等信息;如果是移动事件,则计算移动距离,并根据一定的条件来决定是否拦截事件。

如果没有任何一个子View对该事件进行了处理,则返回false,表示不拦截该事件,让其继续传递给子View进行处理。

以上就是在安卓中使用责任链模式的一个例子,即事件分发机制。在这个机制中,每个子View都是一个责任链节点,它们依次处理触摸事件,并根据具体的情况来决定是否将事件交给下一个节点处理。

总结

责任链模式的优点在于,它能够将一个大型的、复杂的任务分解成多个小的、简单的任务,每个任务都由一个节点来处理,从而降低了系统的复杂性和耦合度。此外,责任链模式还具有灵活性,可以根据具体的需求来动态地调整节点的顺序和个数,从而满足不同的业务场景。

你可能感兴趣的:(Android设计模式应用,java,android,责任链模式,设计模式)