设计模式学习笔记(十六)职责链模式
概念
职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象按照其在链中的顺序依次处理请求,直到有一个对象能够处理请求为止。
比如我们在购物的时候,有这么几个环节:订单验证、库存检查、优惠券验证、支付处理。当不使用职责链模式,最简单的处理方法是用几个if语句来处理
//购物处理类
class ShoppingHandle{
//购物流程开始
public void ShoppingHandle(ShoppingRequest request) {
if (request.getStatus() == 1) {
//订单验证
this.orderValidation(request);
}
else if (request.getStatus() == 2) {
//库存检查
this.inventoryChecking(request);
}
else if (request.getStatus() == 3) {
//优惠券验证
this.couponVerification(request);
}
else {
//支付处理
this.payment(request);
}
}
//订单验证
public void orderValidation(PurchaseRequest request) {}
//库存检查
public void inventoryChecking(PurchaseRequest request) {}
//优惠券验证
public void couponVerification(PurchaseRequest request) {}
//支付处理
public void payment(PurchaseRequest request) {}
}
如果采用此模式,后期维护的时候,如果去掉或增加某个环节,需要修改源代码,违反了开闭原则,而且此类实现后代码量庞大,违反了单一职责原则,因此我们引入了职责链模式。
职责链模式的主要思想是将请求的发送者和接收者解耦,使得多个对象都有机会处理请求。请求在链上传递,直到遇到一个能够处理该请求的对象为止。每个处理对象决定是否能够处理请求以及是否将请求传递给下一个处理对象。 有点类似于双亲委派机制。
● Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。
● ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。
在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
示例
上述示例使用职责链模式的话如图所示
首先定义请求的实体类
/**
* 请求的实体类
* */
public class RequestStream {
private String orderId; //订单编号
private Double Money; //金额
private Integer status; //状态
//省略
public RequestStream(String orderId, Double money, Integer status) {
this.orderId = orderId;
Money = money;
this.status = status;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Double getMoney() {
return Money;
}
public void setMoney(Double money) {
Money = money;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
然后开始定义抽象处理者和具体处理者
//处理者类 用来定义具体处理者的规范
abstract class Processor {
protected Processor nextProcessor; //用来存储 指定的 下一个处理者
protected String userName; //处理者名称
//初始化本次处理者的用户名
public Processor(String userName) {
this.userName = userName;
}
//初始化指定下一个处理者
public void setNextProcessor(Processor nextProcessor) {
this.nextProcessor = nextProcessor;
}
//具体的处理方法,由本次处理者执行
public abstract void processRequest(RequestStream request);
}
//订单验证类
class orderValidation extends Processor {
public orderValidation(String userName) {
super(userName);
}
@Override
public void processRequest(RequestStream request) {
if (request.getStatus() == 1) { //如果匹配成功,那么直接本环节处理
System.out.println("本次订单编号:" + request.getOrderId() + ";金额为:" + request.getMoney() + "的订单-->订单验证已完成");
}else { //如果匹配失败,那么由下一个环节处理
this.nextProcessor.processRequest(request);
}
}
}
//库存检查类
class inventoryChecking extends Processor {
public inventoryChecking(String userName) {
super(userName);
}
@Override
public void processRequest(RequestStream request) {
if (request.getStatus() == 2) { //如果匹配成功,那么直接本环节处理
System.out.println("本次订单编号:" + request.getOrderId() + ";金额为:" + request.getMoney() + "的订单-->库存检查已完成");
}else { //如果匹配失败,那么由下一个环节处理
this.nextProcessor.processRequest(request);
}
}
}
//优惠券验证类
class couponVerification extends Processor {
public couponVerification(String userName) {
super(userName);
}
@Override
public void processRequest(RequestStream request) {
if (request.getStatus() == 3) { //如果匹配成功,那么直接本环节处理
System.out.println("本次订单编号:" + request.getOrderId() + ";金额为:" + request.getMoney() + "的订单-->优惠券验证已完成");
}else { //如果匹配失败,那么由下一个环节处理
this.nextProcessor.processRequest(request);
}
}
}
//支付处理类
class payment extends Processor {
public payment(String userName) {
super(userName);
}
@Override
public void processRequest(RequestStream request) {
if (request.getStatus() == 4) { //如果匹配成功,那么直接本环节处理
System.out.println("本次订单编号:" + request.getOrderId() + ";金额为:" + request.getMoney() + "的订单-->支付处理已完成");
}else { //如果匹配失败,那么由下一个环节处理
this.nextProcessor.processRequest(request);
}
}
}
客户端
Processor zhangsan,lisi,wangwu,liliu;
zhangsan = new orderValidation("张三"); //订单验证者
lisi = new inventoryChecking("李四"); //库存检查者
wangwu = new couponVerification("王五"); //优惠券验证者
liliu = new payment("李六"); //支付处理者
//创建职责链--此处zhangsan为职责链开始
zhangsan.setNextProcessor(lisi);
lisi.setNextProcessor(wangwu);
wangwu.setNextProcessor(liliu);
//开始测试 由职责链开始zhangsan处开始处理
RequestStream p1 = new RequestStream("10001",111.11,1);
zhangsan.processRequest(p1);
RequestStream p2 = new RequestStream("10002",112.11,2);
zhangsan.processRequest(p2);
RequestStream p3 = new RequestStream("10003",113.11,3);
zhangsan.processRequest(p3);
RequestStream p4 = new RequestStream("10004",114.11,4);
zhangsan.processRequest(p4);
执行结果
本次订单编号:10001;金额为:111.11的订单-->订单验证已完成
本次订单编号:10002;金额为:112.11的订单-->库存检查已完成
本次订单编号:10003;金额为:113.11的订单-->优惠券验证已完成
本次订单编号:10004;金额为:114.11的订单-->支付处理已完成
注: 在
zhangsan.setNextProcessor(lisi);
lisi.setNextProcessor(wangwu);
wangwu.setNextProcessor(liliu);
的时候,利用了Processor类中定义了一个自己类的变量,并通过setNextProcessor初始化指定下一个处理者,我们可以将次理解为数据结构里的链表。只不过数据结构的链表是实体里面有一个自己的类,都是类里面包含了自己类型的类。
如果我们想扩充或缩减处理步骤,只需要创建新的处理类,继承抽象处理接口即可。
纯的职责链模式与不纯的职责链模式
职责链模式可以分为纯的职责链模式和不纯的职责链模式,它们的区别在于处理器是否能够自行决定是否将请求传递给下一个处理器。
纯的职责链模式(Pure Chain of Responsibility Pattern):
在纯的职责链模式中,每个处理器都能够自主决定是否将请求传递给下一个处理器。即使一个处理器能够处理请求,但它也可以选择不处理,或者处理完后终止链的传递。这种模式下,处理器之间是松耦合的,它们的顺序可以任意变化。
不纯的职责链模式(Impure Chain of Responsibility Pattern):
在不纯的职责链模式中,处理器无权决定是否将请求传递给下一个处理器,请求会被强制传递给下一个处理器。处理器之间的顺序是固定的,无法随意改变。
通常情况下,我们更常用纯的职责链模式,因为它具有更大的灵活性和扩展性。每个处理器都有机会处理请求,并且可以自由地决定是否将请求传递给下一个处理器,以及何时终止请求的传递。我们上述的例子即为纯职责链模式,通过setNextProcessor方法设置下一个处理者。
不纯的职责链模式可能会导致处理器之间的依赖关系较强,处理器的顺序一旦确定,就难以进行动态调整。这可能会限制系统的灵活性和可维护性。
总结
优点:
1、降低耦合度:将请求发送者和接收者解耦,每个对象只需关注特定的请求类型,对于其他请求可以无视。
2、灵活性和扩展性:可以根据需求动态添加或修改请求处理器,使得系统更具灵活性和可扩展性。
3、可维护性:职责链模式使得系统中的每个处理器只关注自己的业务逻辑,代码更加清晰、简洁,易于维护。
缺点:
1、性能问题:由于请求可能被多个处理者处理,因此有可能会导致性能问题。当处理者的数量过多时,可能会影响请求的处理效率。
2、处理不同的请求需要不同的处理者:如果每种请求都需要单独实现一个处理者,可能会导致类的数量过多,增加系统的复杂度。
适用场景:
1、处理请求需要多个对象进行处理,并且请求处理的顺序不确定,可以根据实际需要动态地改变处理顺序。
2、对象之间需要解耦,希望避免请求发送者和接收者之间的紧密耦合。
3、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
4、可以动态添加或修改请求处理者,提供更大的灵活性和可扩展性。
总之,职责链模式适用于处理复杂的请求场景,在系统拥有多个相似对象且需要按照一定规则处理请求时,可以考虑使用职责链模式。但是在使用时需要注意控制职责链的深度,尽量避免处理器过多引起的性能问题。除此之外,我们还可以用此模式实现过滤器、工作流等