title: Chain of Responsibility模式
tag: 笔记 设计模式
![image-20231107220516047](https://i-blog.csdnimg.cn/blog_migrate/63e6121db31d01c7805b8acab9e8730f.png)
Chain of Responsibility模式
在现实生活中,我们到一些部门办事时可能会遇到各个部门互相转让责任称该事件不由我们部门处理,您应当去找别的部门,我们就像皮球一样被踢来踢去。
这样的事件我们可能都不想遇到,可在程序中,我们可能也存在一个事件不确定由哪个对象来负责。在这样的情况下,我们可以考虑将多个对象组成一条职责链,然后按照它们在职责链上的顺序一个一个地找出到底应该谁来负责处理。
当一个人被要求做什么事情时,如果他可以做就自己做,如果不能做就将“要求”转给另外一个人。下一个人如果可以自己处理,就自己做;如果也不能自己处理,就再转给另外一个人这就是Chain of Responsibility
模式。
介绍
**意图:**避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
**主要解决:**职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
**何时使用:**在处理消息的时候以过滤很多道。
**如何解决:**拦截的类都实现统一接口。
**关键代码:**Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。
使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。
**注意事项:**在 JAVA WEB 中遇到很多应用。
示例程序
该示例程序的作用是处理数字。
UML图:
![image-20231108221743294](https://i-blog.csdnimg.cn/blog_migrate/0f0221eea66e20ce55476047f865e90d.png)
Trouble
:表示问题的类。带有问题编号Support
抽象类:所有解决问题的类的父类。类似数据结果中的链表结构,来组成责任链。LimitSupport
和NoSupport
等类:具体解决问题的类,继承Support
类,组成责任链的具体处理节点。
Trouble类
public class Trouble {
private int num;
public Trouble(int num) {
this.num = num;
}
public int getNum() {
return num;
}
@Override
public String toString() {
return "Trouble[" +
"num=" + num +
']';
}
}
用来表示问题的类,带有一个编号。
Support抽象类
public abstract class Support {
private final String name;
private Support next;
public Support(String name) {
this.name = name;
}
public Support setNext(Support next) {
this.next = next;
return next;
}
public void support(Trouble trouble) {
if (resolve(trouble)) {
done(trouble);
} else if(next != null) {
next.support(trouble);
}else{
fail(trouble);
}
}
protected void done(Trouble trouble) {
System.out.println(trouble.toString() + "被" + name + "解决");
}
protected void fail(Trouble trouble) {
System.out.println(trouble.toString() + " 没有人能够解决");
}
public abstract boolean resolve(Trouble trouble);
}
所有责任节点的父类,其结构如下:
-
属性
name
:表示该责任节点的名字next
:表示该责任节点的下一个节点
-
方法
-
setNext
:设置下一个节点,并返回下一个节点 -
support
:责任链可以解决问题- 能解决则解决
- 不能解决则交给下一个节点解决
- 若到了节点最后,则说明该问题不能解决
-
done
:该节点解决问题 -
fail
:该问题不能被解决 -
resolve
:抽象方法,具体解决方法的处理交由子类。
-
父类定义了应该做什么,而将怎么做交给了子类来具体实现。
LimitSupport等具体实现类
public class LimitSupport extends Support{
private int limit;
public LimitSupport(String name, int limit) {
super(name);
this.limit = limit;
}
@Override
public boolean resolve(Trouble trouble) {
return trouble.getNum() < limit;
}
}
public class NoSupport extends Support{
public NoSupport(String name) {
super(name);
}
@Override
public boolean resolve(Trouble trouble) {
return false;
}
}
public class OddSupport extends Support{
public OddSupport(String name) {
super(name);
}
@Override
public boolean resolve(Trouble trouble) {
return trouble.getNum() % 2 != 0;
}
}
public class SpecialSupport extends Support{
private int num;
public SpecialSupport(String name,int num) {
super(name);
this.num = num;
}
@Override
public boolean resolve(Trouble trouble) {
return num == trouble.getNum();
}
}
这些类都重写了resolve
解决问题的方法,返回boolean值表示自己能否解决该问题。
测试
public static void main(String[] args) {
//解决问题的节点
LimitSupport ming = new LimitSupport("小明",20);
NoSupport ben = new NoSupport("小笨");
OddSupport hong = new OddSupport("小红");
SpecialSupport gang = new SpecialSupport("小刚", 98);
//将节点组成一个链表
ming.setNext(ben).setNext(hong).setNext(gang);
//测试
for (int i = 0; i < 100; i++) {
ming.support(new Trouble(i));
}
}
在这个类中我们实例化了四个处理问题的节点,并将这些节点组成了一个链表。然后我们从头节点(小明),就可以拿到所有的节点。
输出:
......
Trouble[num=16]被小明解决
Trouble[num=17]被小明解决
Trouble[num=18]被小明解决
Trouble[num=19]被小明解决
Trouble[num=20] 没有人能够解决
Trouble[num=21]被小红解决
Trouble[num=22] 没有人能够解决
Trouble[num=23]被小红解决
Trouble[num=24] 没有人能够解决
Trouble[num=25]被小红解决
Trouble[num=26] 没有人能够解决
Trouble[num=27]被小红解决
......
测试结果与我们的预期相同。
Chain of Responsibility中的角色
Handler(处理者)
Handler
角色定义了处理请求的接口(API)。Handler
角色知道“下一个处理者”是谁,如果自己无法处理请求,它会将请求转给“下一个处理者”。当然,“下一个处理者”也是Handler
角色。在示例程序中,由Support
类扮演此角色。负责处理请求的是support
方法。
ConcreteHandler(具体的处理者)
Concrete Visitor
角色是处理请求的具体角色。在示例程序中,由NoSupport
、LimitSupport
、OddSupport
、SpecialSupport
等各个类扮演此角色。
Client(请求者)
**Client
角色是向第一个ConcreteHandler
角色发送请求的角色。**在示例程序中,由Main类扮演此角色。
该模式下的UML类图:
![image-20231109102851195](https://i-blog.csdnimg.cn/blog_migrate/f4b0ed668f225efa9732b83cd5fa601d.png)
扩展思路
弱化了请求和处理请求之间的关系
Chain of Responsibility
模式中最显著的特点即为弱化了请求的程序(Client)
与处理请求的人(ConcreteHandler)
之间的关系。Client
只需要将问题丢给责任链的头节点后,请求就会在责任链之间传播。
若不使用责任链模式,则在Client请求前就需要知道该问题应当交由具体哪一个类来处理。
-20231109102851195" style=“zoom: 80%;” />
扩展思路
弱化了请求和处理请求之间的关系
Chain of Responsibility
模式中最显著的特点即为弱化了请求的程序(Client)
与处理请求的人(ConcreteHandler)
之间的关系。Client
只需要将问题丢给责任链的头节点后,请求就会在责任链之间传播。
若不使用责任链模式,则在Client请求前就需要知道该问题应当交由具体哪一个类来处理。