去年这时候就在写设计模式的文章了,但是没写完,有好几个没有写,现在打算继续写,争取把设计模式写完,本来这些很简单的模式我打算一篇写几个的,但是还是遵从单一职责原则,每篇文章写一个比较好.
责任链模式定义
责任链模式很简单,我们看它的英文名”Iterator Pattern”,我觉得直接叫他迭代器模式
拉倒了.就是一个请求沿着一条“链”传递,直到该“链”上的某个处理者处理它为止。这种情况在编程中很常见,当我们的服务对象有多个的时候,很容易遇到.
责任链模式应用场景
一个请求可以被多个处理者处理或处理者未明确指定时,具体由哪个对象处理由运行时动态的决定.
责任链模式简单使用
针对上面的说的应用场景,可以很简单的模拟出场景,我有一个事情有3个对象有权处理,具体处理要看这三个对象是否处理了.
我正在听JJ的”末班车”,想到了个例子,我们要上班,小明家门口的站牌有三路公交车711,712,718都可以到公司,那么小明站到站台后,这三路公交车就构成了上面的情况,多个处理者,且处理情况动态决定.那这种代码的编写是什么情况呢?
我们定义小明具有上车功能,车具有接人功能.
/** 上车接口 */
interface GetOn {
void getOn();
}
/** 人,具有上车属性 */
class Person implements GetOn {
public void getOn() {
}
}
/** 接人接口,接想上车的人 */
interface Pickup {
boolean pickUp(GetOn on);
}
定义三辆车
class Car711 implements Pickup {
public boolean pickUp(GetOn on) {
System.out.println("711车没满,能上车");
return true;
}
}
class Car712 implements Pickup {
public boolean pickUp(GetOn on) {
System.out.println("712车满,上车失败");
return false;
}
}
class Car718 implements Pickup {
public boolean pickUp(GetOn on) {
System.out.println("718车没满,能上车");
return false;
}
}
这时候模拟一下运行情况,假设是712先来的.
public static void main(String[] args) {
GetOn xiaoming = new Person();
Car711 car711 = new Car711();
Car712 car712 = new Car712();
Car718 car718 = new Car718();
if (car712.pickUp(xiaoming)) {
System.out.println("小明上712了");
} else if (car711.pickUp(xiaoming)) {
System.out.println("小明上711了");
} else if (car718.pickUp(xiaoming)) {
System.out.println("小明上718了");
}
}
结果为:
712车满,上车失败
711车没满,能上车
小明上711了
这就是一个简单的责任链模式demo,但事实上我们程序肯定不是这么写的,车可能有很多,然而都注册进一个表里面的.情况多了,就发现这么设计的优点真的好.
责任链模式源码应用
Android源码设计里面的触摸事件的分发就是采用的责任链模式,一层一层的分发下去,直到有人处理了,就终止了.
我们可以看看ViewGroup
里面的事件分发.
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
...
boolean handled = false;
if (onFilterTouchEventForSecurity(ev)) {
....
/*
* 如果事件未被取消并未被拦截
*/
if (!canceled && !intercepted) {
/*
* 如果事件为起始事件
*/
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
// 省掉部分逻辑…………
final int childrenCount = mChildrenCount;
/*
* 如果TouchTarget为空并且子元素不为0
*/
if (newTouchTarget == null && childrenCount != 0) {
final float x = ev.getX(actionIndex);
final float y = ev.getY(actionIndex);
final View[] children = mChildren;
final boolean customOrder = isChildrenDrawingOrderEnabled();
/*
* 遍历子元素
*/
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = customOrder ?
getChildDrawingOrder(childrenCount, i) : i;
final View child = children[childIndex];
/*
* 如果这个子元素无法接收Pointer Event或这个事件点压根就没有落在子元素的边界范围内
*/
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
// 那么就跳出该次循环继续遍历
continue;
}
// 找到Event该由哪个子元素持有
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
/*
* 投递事件执行触摸操作
* 如果子元素还是一个ViewGroup则递归调用重复此过程
* 如果子元素是一个View那么则会调用View的dispatchTouchEvent并最终由onTouchEvent处理
*/
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
mLastTouchDownTime = ev.getDownTime();
mLastTouchDownIndex = childIndex;
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
/*
* 如果发现没有子元素可以持有该次事件
*/
if (newTouchTarget == null && mFirstTouchTarget != null) {
newTouchTarget = mFirstTouchTarget;
while (newTouchTarget.next != null) {
newTouchTarget = newTouchTarget.next;
}
newTouchTarget.pointerIdBits |= idBitsToAssign;
}
}
}
...
}
...
return handled;
}
具体分发机制在之前的浅析Android触摸事件分发机制就讲过了
ViewGroup事件投递的递归调用就类似于一条责任链,责任就是消费触摸事件.,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体的体现在View的onTouchEvent方法中返回值的设置,如果onTouchEvent返回false那么意味着当前View不会是该次事件的责任人将不会对其持有,如果为true则相反,此时View会持有该事件并不再向外传递。
带来的问题
万事都有其不足,甚至完美的东西都有缺点,那就是他没有缺点.责任链模式也有其缺点: 最大的缺点是当责任人层次太多,责任人太多时,性能问题
本文作者:Anderson/Jerey_Jobs
博客地址 : http://jerey.cn/
简书地址 : Anderson大码渣
github地址 : https://github.com/Jerey-Jobs