定义:
使多个对象都有机会处理请求,从而避免请求者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止
类型:
行为型
理解:
- 定义多个请求接收者,然后把他们连接成一条链,也就是每个接受者对象里都引用了下一个接收者对象
- 当发起一个请求时,链条的第一个接收者开始处理,如果它判断能够处理,则请求到此为止,如果不能处理,则传递给下一个接收者处理
- 直到有一个接收者处理了该请求或者所有的接收者都无法处理为止
- 该设计模式可以用来消除大量的if/else代码
- 生活中很多类似的例子,比如公司里的审批、报销等流程
生活中我们有时候需要点外卖,比如想吃肯德基,可能会遇到网上找了几家肯德基店要么距离远不配送,要么就没有我们想吃的这样的问题,浪费了很多时间,其实这个问题就可以用责任链模式来解决,解决问题的思路是这样的:
把不同的肯德基分店当作一个个请求接收者,将这些分店连成链状,当有订单来的时候,各个分店一个个判断能不能接单,如果能接单则开始制作配送外卖,如果不能则传递给下一个肯德基分店处理,这样用户只需要发起一个肯德基订单请求,只需要等待结果就好了,如果没有一家肯德基接单,就不吃肯德基换成其他的了,节省了很多等待和沟通成本
/**
* 订单信息
* @param distance 配送位置
*/
class Order(val distance:Int) {
}
/**
* 店铺
*/
abstract class Shop(name: String, distance: Int) {
var mNextShop: Shop? = null //下一家分店
protected val mDistance = distance//距离
protected val mName = name//店名
abstract fun order(order: Order):Boolean
}
/**
* 肯德基分店
*
* @author zhujie
* @date 2019/6/6
* @time 11:36
*/
class KfcShop(name: String, distance: Int) : Shop(name, distance) {
override fun order(order: Order): Boolean {
if (order.distance < mDistance) {//在配送范围
Tool.print("[$mName] 已接单!请耐心等待!")
return true
}
Tool.print("[$mName] 不在配送范围!")
if (mNextShop != null) {
return mNextShop!!.order(order)
} else {
Tool.print("没找到可以配送的店")
}
return false
}
}
/**
* 店铺管理
*
* @author zhujie
* @date 2019/6/6
* @time 12:25
*/
class ShopManager {
private var mStartShop: Shop? = null//链首
private lateinit var mEndShop: Shop//链尾
init {
Tool.print("初始化分店数据")
val subShop1 = KfcShop("KFC分店1", 20)//分店1
val subShop2 = KfcShop("KFC分店2", 30)//分店2
val subShop3 = KfcShop("KFC分店3", 40)//分店3
val subShop4 = KfcShop("KFC分店4", 50)//分店4
val subShop5 = KfcShop("KFC分店5", 60)//分店5
addShop(subShop1)
addShop(subShop2)
addShop(subShop3)
addShop(subShop4)
addShop(subShop5)
}
/**
* 添加一个分店
*/
fun addShop(shop: KfcShop) {
if (mStartShop == null) {
mStartShop = shop
mEndShop = shop
} else {
mEndShop.mNextShop = shop
mEndShop = shop
}
}
/**
* 开始下单
*/
fun order(order: Order): Boolean {
if (mStartShop == null) {
return false
}
return mStartShop!!.order(order)
}
}
相比较标准责任链模式,这个例子当中多了一个ShopManager管理类,用于管理所有分店,将分店组装成链式结构
运行结果:
2019-08-30 17:50:04.150:初始化分店数据
2019-08-30 17:50:04.152:[KFC分店1] 不在配送范围!
2019-08-30 17:50:04.153:[KFC分店2] 不在配送范围!
2019-08-30 17:50:04.153:[KFC分店3] 不在配送范围!
2019-08-30 17:50:04.153:[KFC分店4] 不在配送范围!
2019-08-30 17:50:04.153:[KFC分店5] 已接单!请耐心等待!
Process finished with exit code 0
类结构图如下:
Android_129">Android中的责任链模式:
当看到责任链模式之后,相信很多朋友第一反应就是跟Android的触摸事件分发非常的相似!Android中的触摸事件,先从最顶层的ViewGroup开始,一直往下分发到各个子View里面,大致的逻辑是这样:
- 如果某个ViewGroup想要处理这个触摸事件,则在onInterceptTouchEvent中返回true拦截该事件,该事件就不会再分发给子view,会调用该ViewGroup的onTouch方法,该onTouch方法返回true,表示消耗当前事件,否则的话会将给事件传回给父类处理
- 如果ViewGroup不想处理该触摸事件,则分发给它的子View,如果子View的onTouch方法返回true,表示消化该事件,触摸事件就到此结束
- 如果子view都不想处理该事件,那么就会一层一层的往上抛给他们的父类viewGroup,调用他们的onTouch方法,如果有其中一个viewGroup的onTouch返回了true,则该事件处理完毕,不再传播
- 如果没有任何一个ViewGroup需要处理,这个触摸事件就会一层层返回到最顶层的ViewGroup,最后由Activity的onTouch方法处理
- 如果View设置了onTouchListener,它执行的优先级比onTouchEvent要高,如果onTouchListener中的onTouch方法返回false,则View的onTouchEvent方法不会被执行
- 触摸事件传递的顺序是:Activity->Window(PhoneWindow)->View(DecorView)
- 同一个事件序列是从屏幕触摸到屏幕ACTION_DOWN开始的,经过0个或者多个ACTION_MOVE移动事件,最后离开屏幕ACTION_UP/ACTION_CANCEL结束
- 正常情况下一个事件序列只能被一个View拦截处理消耗掉,如果处理了ACTION_DOWN事件,那么其他事件也会一起交给它处理,也就是onTouchEvent事件返回true,反之如果返回false,则接下来的其他事件都不会交给它处理,就好像现实生活中,领导交给你第一件事都没做好,其他事情暂时也不会交给你做
- 如果ViewGroup的onInterceptTouchEvent返回了true,那么同一个事件其他序列也会交给它处理,而且不会再回调onInterceptTouchEvent这个方法
- 如果View不消耗除了ACTION_DOWN以外的事件,那么这个点击事件就会消失,父元素的onTouchEvent也不会回调,但是当前view能够接收到后续的触摸事件,最终这些消失的点击事件会传递回给Activity处理
- view没有onInterceptTouchEvent方法,只有ViewGroup有,一旦事件传递给View,它的onTouchEvent就会触发
- View的onTouchEvent默认是返回true的,除非它是不可点击状态(clickable和longClickable同时为false),View的longClickable默认都是false的,而clickable在Button里默认是true的,像TextView默认就是false
- View的enable属性并不影响onTouchEvent的返回值
- onClick执行的前提是当前View是可点击的,并且接收到ACTION_DOWN和ACTION_UP事件
- 触摸事件总是由父元素分发给子View的,子View可以通过requestDisallowInterceptTouchEvent方法在禁止父类拦截事件,但是ACTION_DOWN事件除外
优点:
- 将请求者和接收者解耦,使得请求者不需要了解到是谁处理了这个请求,也不需要了解处理的内部细节
- 由于链式结构的特点,使得动态增加、删除或者调整处理者顺序很容易
缺点:
- 不能保证请求一定最终被处理
- 当处理者过多的时候,可能会有性能方面问题