摘要:本文用一个实例场景描述Gof 23设计模式中的责任链模式,并用Quarkus框架代码给予实现,同时也给出实现代码的UML模型。
关键字:Gof 23 设计模式 责任链模式 Quarkus
1 基础知识
1.1 标准定义
责任链(Chain of Responsibility)模式标准定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
1.2 分析和说明
责任链(Chain of Responsibility)模式属于行为型设计模式。在责任链模式中,各种服务组合或对象由没一个服务或对象对其下家的引用而接起来形成一个整体的系统链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。职责链可以提高系统的灵活性,通过配置多变的职责链可以完成系统功能的扩充或改变,保证系统的可移植性。
责任链(Chain of Responsibility)模式结构如图1所示,其角色包括抽象处理者(Handler)角色和具体处理者(Concrete Handler)角色。
图1 责任链模式结构
抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义出一个方法,以设定和返回对下家的引用。这个角色通常由一个抽象类或者接口实现。图中的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
具体处理者(Concrete Handler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
2 应用场景举例
比如公司技术部门有几位技术高手,当菜鸟在工作中遇到了问题,于是向这些高手们请教,如果第一位高手能解决问题,那这个过程就结束,否则传递给下一个高手,下一个高手也是同样操作,不能解决问题就再交给下下一位。这样,要么这些高手里其中一个能解决问题,要么这些高手全都不能解决这个问题,这就是责任链模式。用例如图2所示。
图2 责任链模式用例图
在这里可以把AbstractSuperMan抽象类理解为抽象处理者(Handler)角色。SuperManOne类,SuperManTwo类和SuperManThree类是具体处理者(Concrete Handler)角色。其结构类图如图3所示。SuperManOne类,SuperManTwo类和SuperManThree类继承AbstractSuperMan抽象类。AbstractSuperMan抽象类进行自我关联。
图3 责任链模式类图
责任链模式实现顺序图见图4,实现顺序描述:① 基于SuperManOne类创建一个superMan1对象;② 基于SuperManTwo类创建一个superMan2对象;③ 基于SuperManThree类创建一个superMan3对象;④基于PrimaryMan类创建一个primaryMan对象;⑤ 调用superMan1对象的setSuccessorSuperMan方法,把superMan2对象设置为superMan1对象的下一个链条;⑥ 调用superMan2对象的setSuccessorSuperMan方法,把superMan3对象设置为superMan2对象的下一个链条;⑦ 调用superMan3对象的setSuccessorSuperMan方法,把superMan1对象设置为superMan3对象的下一个链条;⑧ 给primaryMan对象设置标准答案;⑨ primaryMan对象向superMan1对象请求答案;不能解答后转到superMan2对象,最后转到superMan3对象;⑩ superMan3对象正确回答问题并返回答案。
图4 责任链模式实现顺序图
3.Quarkus的实现程序代码
Quarkus程序实现主要包括AbstractSuperMan抽象类文件,PrimaryMan类文件,SuperManOne类文件,SuperManTwo类文件和SuperManThree类文件等5个文件。其关系如图3所示。下面分别列出这4个文件的程序代码,最后列出测试代码并显示输出结果。
AbstractSuperMan抽象类程序代码清单01所示。
程序代码清单01
public abstract class AbstractSuperMan {
protected String answer;
protected AbstractSuperMan successorSuperMan;
public String getAnswer() {return answer;}
public void setAnswer(String answer) {this.answer = answer;}
public AbstractSuperMan getSuccessorSuperMan() {return successorSuperMan;
public void setSuccessorSuperMan(AbstractSuperMan successorSuperMan) {
this.successorSuperMan = successorSuperMan;
}
public void answerTheQuestion(PrimaryMan man){}
}
PrimaryMan类程序代码清单02所示。
程序代码清单02
@ApplicationScoped
public class PrimaryMan {
private String thisAnswer ;
public boolean question(String answer){
if (thisAnswer.equals(answer)) return true;
return false ;
}
public String getThisAnswer() {
return thisAnswer;
}
public void setThisAnswer(String thisAnswer) {
this.thisAnswer = thisAnswer;
}
}
SuperManOne类,SuperManTwo类和SuperManThree类继承AbstractSuperMan抽象类,其程序代码清单03所示。
程序代码清单03
@ApplicationScoped
public class SuperManOne extends AbstractSuperMan {
private boolean isAnswer = false;
public void answerTheQuestion(PrimaryMan man) {
if (man.question(answer)) {
System.out.println("SuperManOne回答正确。");
} else {
if (isAnswer)
System.out.println("大家都不能回答这个问题。");
else {
isAnswer = true;
if (successorSuperMan != null) {
System.out.println("SuperManOne不会回答问题,提交下一个。");
successorSuperMan.answerTheQuestion(man);
}
}
}
}
}
@ApplicationScoped
public class SuperManTwo extends AbstractSuperMan{
private boolean isAnswer = false;
public void answerTheQuestion(PrimaryMan man){
if (man.question(answer)) {
System.out.println("SuperManTwo回答正确。");
} else {
if (isAnswer)
System.out.println("大家都不能回答这个问题。");
else {
isAnswer = true;
if (successorSuperMan != null) {
System.out.println("SuperManTwo不会回答问题,提交下一个。");
successorSuperMan.answerTheQuestion(man);
}
}
}
}
}
@ApplicationScoped
public class SuperManThree extends AbstractSuperMan{
private boolean isAnswer = false;
public void answerTheQuestion(PrimaryMan man){
if (man.question(answer)) {
System.out.println("SuperManThree回答正确。");
} else {
if (isAnswer)
System.out.println("大家都不能回答这个问题。");
else {
isAnswer = true;
if (successorSuperMan != null) {
System.out.println("SuperManThree不会回答问题,提交下一个。");
successorSuperMan.answerTheQuestion(man);
}
}
}
}
}
责任链模式测试程序的代码清单04如下:
程序代码清单04
public class ChainofresponsibilityClient implements QuarkusApplication {
@ConfigProperty(name = "gof23.behavioralpattern.chainofresponsibility.title", defaultValue = "gof23")
String title;
@Inject SuperManOne superMan1;
@Inject SuperManTwo superMan2;
@Inject SuperManThree superMan3;
@Inject PrimaryMan primaryMan;
@Override
public int run(String... args) {
System.out.println("——————" + title + "演示输出—————————");
//形成一个闭环的链
superMan1.setSuccessorSuperMan(superMan2);
superMan2.setSuccessorSuperMan(superMan3);
superMan3.setSuccessorSuperMan(superMan1);
//设置提问者的问题和答案
primaryMan.setThisAnswer("ANSWER");
//让superMan1能回答这个答案
superMan1.setAnswer("ANSWER1");
//让superMan2能回答这个答案
superMan2.setAnswer("ANSWER2");
//让superMan3能回答这个答案
superMan3.setAnswer("ANSWER");
superMan1.answerTheQuestion(primaryMan);
return 0;
}
public static void main(String... args) {
Quarkus.run(ChainofresponsibilityClient.class, args);
}
}
责任链模式测试类输出结果如下所示:
SuperManOne不会回答问题,提交下一个。
SuperManTwo不会回答问题,提交下一个。
SuperManThree回答正确。
4. 相关Quarkus程序源码下载
可以直接从github上获取代码,读者可以从github上clone预先准备好的示例代码。
git clone https://github.com/rengang66/quarkus-sample-gof23.git
这是一个Maven项目,然后Maven导入工程。该程序位于“src\main\java\com\iiit\quarkus\sample\gof23\behavioralpattern\chainofresponsibility”目录中。
同时也可以从gitee上clone预先准备好的示例代码,命令如下:
git clone https://gitee.com/rengang66/quarkus-sample-gof23.git
参考文献
[1] E.Gamma, R.Helm, R.Johnson, and Vlissides. Design Patterns Elements of Reusable Object Oriented Software. Addison-Wesley, 1995
[2] E.Gamma, R.Helm, R.Johnson, and Vlissides.著,李英军等译,设计模式:可复用面向对象软件的基础,北京:机械工业出版社.2000.9.
[3] 阎宏,Java与模式,北京:电子工业出版社. 2002.10
[4] 王俊峰 戚晓滨. 设计模式和UML. 计算机应用研究,1999.16(5), 27-29,39.
[5] 陈琴 朱正强. UML在设计模式描述中的应用. 计算机工程与设计,2003.24(4), 81-84.
[6] 郭庆华 刘镰斧. 设计模式在网元管理系统的应用. 福建电脑,2005.(12),31-31,22.
[7] 万波 张焰 罗治强. 设计模式在Drawcli程序中的应用. 计算机应用与软件,2003.20(8), 12-13,84.
[8] 顾明. 基于软件设计模式的GIS中间件描述. 计算机应用与软件,2008.25(3), 86-88.
[9] 何江玲 孙其博. 设计模式在软交换软件系统中的应用. 世界电信,2003.16(9), 42-44.
[10] 肖志峰 龚健雅 王艳东 翟晓芳. 面向对象的软件设计模式在配电GIS中的应用. 测绘信息与工程,2005.30(3), 3-5.
[11] 陈贺明[1] 王彩玲[2]. MFC中设计模式(Design Pattern)简析. 河南广播电视大学学报,2006.19(3), 50-52.
[12] Quarkus官网. https://quarkus.io/