行为设计模式 -责任链模式- JAVA
前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。
作者:神的孩子都在歌唱
一 .简介
百度百科:责任链模式是一种行为设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
个人理解: 通过责任链方式可以找到能够处理客户端请求的对象。感觉就跟Switch 或者try-catch 一样,当前不匹配就继续往下匹配。
责任链模式涉及到的角色如下所示:
● 抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
● 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
二. 案例
网上看了很多案例,感觉ATM取款机这个案例最容易理解。需求是让用户输入一个金额数(amount),然后ATM机会将输入的金额数从大到小(能够分配的纸币类型是100元 20 元 10元)进行分配。如果用户输入的金额不是10的倍数,就抛出错误。
其实这个实现起来很简单,不过为了将每种类型的纸币进行解耦,所以需要使用责任链方式去解决
2.1 抽象处理者(Handler)角色
定义分配的处理链接口
/**
* @author chenyunzhi
* @date 2024/6/4 16:27
* @Description 分配的处理链接口
*/
public interface DispenseChain {
/**
* 要执行的下一个链(对象)
*/
void setNextChain(DispenseChain nextChain);
/**
* 执行分配的方法
*/
void dispense(Integer amount);
}
2.2 具体处理者(ConcreteHandler)角色
定义每种纸币的对象
Yuan100Dispenser
/**
* @author chenyunzhi
* @date 2024/6/4 16:30
* @Description
*/
public class Yuan100Dispenser implements DispenseChain{
private DispenseChain dispenseChain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.dispenseChain = nextChain;
}
@Override
public void dispense(Integer amount) {
if (amount >= 100) {
int num = amount / 100;
int remainder = amount % 100;
System.out.println("分配了" + num + "张100元");
// 进入下一个分配
if (remainder != 0) {
this.dispenseChain.dispense(remainder);
}
} else {
this.dispenseChain.dispense(amount);
}
}
}
Yuan20Dispenser
/**
* @author chenyunzhi
* @date 2024/6/4 16:30
* @Description
*/
public class Yuan20Dispenser implements DispenseChain{
private DispenseChain dispenseChain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.dispenseChain = nextChain;
}
@Override
public void dispense(Integer amount) {
if (amount >= 20) {
int num = amount / 20;
int remainder = amount % 20;
System.out.println("分配了" + num + "张20元");
// 进入下一个分配
if (remainder != 0) {
this.dispenseChain.dispense(remainder);
}
} else {
this.dispenseChain.dispense(amount);
}
}
}
Yuan10Dispenser
/**
* @author chenyunzhi
* @date 2024/6/4 16:30
* @Description
*/
public class Yuan10Dispenser implements DispenseChain{
private DispenseChain dispenseChain;
@Override
public void setNextChain(DispenseChain nextChain) {
this.dispenseChain = nextChain;
}
@Override
public void dispense(Integer amount) {
if (amount >= 10) {
int num = amount / 10;
int remainder = amount % 10;
System.out.println("分配了" + num + "张10元");
// 进入下一个分配
if (remainder != 0) {
this.dispenseChain.dispense(remainder);
}
} else {
this.dispenseChain.dispense(amount);
}
}
}
2.3 测试
这一步我们将三种纸币连接起来,创建链进行测试
/**
* @author chenyunzhi
* @date 2024/6/4 16:48
* @Description 测试
*/
public class ChainOfResponsibilityPatternTest {
private DispenseChain chain;
/**
* 初始化atm分配链
*/
public ChainOfResponsibilityPatternTest() {
this.chain = new Yuan100Dispenser();
Yuan20Dispenser yuan20Dispenser = new Yuan20Dispenser();
Yuan10Dispenser yuan10Dispenser = new Yuan10Dispenser();
chain.setNextChain(yuan20Dispenser);
yuan20Dispenser.setNextChain(yuan10Dispenser);
}
public static void main(String[] args) {
ChainOfResponsibilityPatternTest patternTest = new ChainOfResponsibilityPatternTest();
for (int i=0; i<3; i++){
System.out.println("----------输入领取金额-----------");
Scanner scanner = new Scanner(System.in);
int amount = scanner.nextInt();
if (amount % 10 != 0) {
System.out.println("需要输入10的倍数的金额");
continue;
}
patternTest.chain.dispense(amount);
System.out.println("----------分配结束-----------");
}
}
}
通过上面的组装链,就能够将atm的需求实现了。
三. 结论
3.1 优缺点
1,优点:
-
降低了对象之间的耦合度: 该模式降低了请求发送者和接收者的耦合度。
-
增强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。
-
增强了给对象指派职责的灵活性:当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。
-
责任链简化了对象之间的连接:一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
-
责任分担:每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
2,缺点:
-
不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
-
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
-
职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
3.2 示例
-
java.util.logging.Logger#log()
-
javax.servlet.Filter#doFilter()
3.3 要点
-
-
客户端不知道链的哪一部分将处理请求,它会将请求发送到链中的第一个对象
作者:神的孩子都在歌唱
本人博客:https://blog.csdn.net/weixin_46654114
- 点赞
- 收藏
- 关注作者
评论(0)