【一】介绍引入
- 当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式(Chain of Responsibility Pattern)。
【二】场景引入
- 自从推出Java版本的糖果机之后,万能糖果公司收到的电子邮件数量已超出他们所能处理的范围。
- 据他们自己分析,所收到的电子邮件有四类:
- 其一、Fans寄来的信,他们喜欢新推出的l in 10游戏;
- 其二,父母寄来的信,抱怨他们的孩子沉溺于这个游戏;
- 其三,店家寄来的信,他们希望能够在某些地方也摆设糖果机;
- 其四,垃圾邮件。
- 所有Fans的邮件都需要直接送到CEO手上,所有的抱怨邮件则是送给法律部门,而所有的新机器请求邮件则交给业务部门,至于垃圾邮件当然是删除了事。
【三】任务需求
- 万能糖果公司已经写了一些人工智能过滤程序,这些程序很厉害,它们会分辨邮件是属于上述哪一类
- 但是他们需要你构造一个设计——使用这个过滤程序处理收到的邮件。
【四】如何使用责任链模式
- 责任链模式是一种行为设计模式,用于构建一条对象链,每个对象都包含了对请求的处理方式。
- 当一个请求被发送到这个链上,每个对象都会依次尝试处理请求,直到其中一个对象处理成功或者所有对象都不能处理为止。
- 责任链模式的核心思想是将请求的发送者和接收者解耦,使多个对象都有机会处理请求,避免了将请求的发送者与接收者紧密耦合在一起。
- 责任链模式通常包括以下角色
- Handler(处理者): 定义了处理请求的接口,通常包括一个处理方法。具体的处理者对象实现这个接口,并决定是否能够处理请求,如果能够处理,则进行处理;如果不能处理,则将请求传递给下一个处理者。
- ConcreteHandler(具体处理者): 具体的处理者对象,实现了Handler接口,负责处理请求。如果自己能够处理请求,则进行处理;否则,将请求传递给下一个处理者。
- Client(客户端): 创建处理者链并向链中的第一个处理者发送请求。
【五】责任链模式的优点
- 将请求的发送者和接受者解耦。
- 可以简化你的对象,因为它不需要知道链的结构。
- 通过改变链内的成员或调动它们的次序,允许你动态地新增或者删除责任。
- 可以避免请求发送者需要知道接收者的详细信息,降低了耦合度。
【六】责任链模式的用途和缺点
- 经常被使用在窗口系统中,处理鼠标和键盘之类的事件。
- 并不保证请求一定会被执行:如果没有任何象处理它的话,它可能会落到链尾端之外(这可以是优点也可以是缺点)。
- 可能不容易观察运行时的特征,有碍于除错。
【七】代码演示
【1】理论
-
Handler
- successor
- handleRequest()
-
SpanHandler
- handleRequest()
-
FanHandler
- handleRequest()
-
ComplaintHandler
- handleRequest()
-
NewLocalHandler
- handleRequest()
-
链中的每个对象扮演处理器,并且都有一个后继对象
-
如果他可以处理请求,就进行处理;否则把请求传给后继者
-
当收到电子邮件的时候,它会被送进第一个处理器,也就是SpamHandler。如果SpamHandler无法处理,就将它传给FanHandler。依次类推……
【2】Java代码
// 定义邮件处理器接口
public interface EmailHandler {
void setNextHandler(EmailHandler handler);
void handleEmail(Email email);
}
// 实现垃圾邮件处理器
public class SpamHandler implements EmailHandler {
private EmailHandler nextHandler;
@Override
public void setNextHandler(EmailHandler handler) {
this.nextHandler = handler;
}
@Override
public void handleEmail(Email email) {
if (isSpam(email)) {
System.out.println("Deleted spam email: " + email.getContent());
} else if (nextHandler != null) {
nextHandler.handleEmail(email);
}
}
private boolean isSpam(Email email) {
// 判断邮件是否是垃圾邮件的逻辑
// 这里只是一个示例,实际逻辑需要根据具体情况编写
return email.getContent().contains("spam");
}
}
// 实现Fans邮件处理器
public class FansHandler implements EmailHandler {
private EmailHandler nextHandler;
@Override
public void setNextHandler(EmailHandler handler) {
this.nextHandler = handler;
}
@Override
public void handleEmail(Email email) {
if (isFansEmail(email)) {
System.out.println("Forwarded fans email to CEO: " + email.getContent());
} else if (nextHandler != null) {
nextHandler.handleEmail(email);
}
}
private boolean isFansEmail(Email email) {
// 判断邮件是否是Fans邮件的逻辑
// 这里只是一个示例,实际逻辑需要根据具体情况编写
return email.getContent().contains("fans");
}
}
// 实现抱怨邮件处理器
public class ComplaintHandler implements EmailHandler {
private EmailHandler nextHandler;
@Override
public void setNextHandler(EmailHandler handler) {
this.nextHandler = handler;
}
@Override
public void handleEmail(Email email) {
if (isComplaintEmail(email)) {
System.out.println("Forwarded complaint email to legal department: " + email.getContent());
} else if (nextHandler != null) {
nextHandler.handleEmail(email);
}
}
private boolean isComplaintEmail(Email email) {
// 判断邮件是否是抱怨邮件的逻辑
// 这里只是一个示例,实际逻辑需要根据具体情况编写
return email.getContent().contains("complaint");
}
}
// 实现新机器请求邮件处理器
public class NewMachineRequestHandler implements EmailHandler {
private EmailHandler nextHandler;
@Override
public void setNextHandler(EmailHandler handler) {
this.nextHandler = handler;
}
@Override
public void handleEmail(Email email) {
if (isNewMachineRequestEmail(email)) {
System.out.println("Forwarded new machine request email to business department: " + email.getContent());
} else if (nextHandler != null) {
nextHandler.handleEmail(email);
}
}
private boolean isNewMachineRequestEmail(Email email) {
// 判断邮件是否是新机器请求邮件的逻辑
// 这里只是一个示例,实际逻辑需要根据具体情况编写
return email.getContent().contains("new machine request");
}
}
// 定义Email类
public class Email {
private String content;
public Email(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建邮件处理器
EmailHandler spamHandler = new SpamHandler();
EmailHandler fansHandler = new FansHandler();
EmailHandler complaintHandler = new ComplaintHandler();
EmailHandler newMachineRequestHandler = new NewMachineRequestHandler();
// 构建责任链
spamHandler.setNextHandler(fansHandler);
fansHandler.setNextHandler(complaintHandler);
complaintHandler.setNextHandler(newMachineRequestHandler);
// 模拟收到不同类型的邮件并处理
Email email1 = new Email("This is a fans email.");
Email email2 = new Email("This is a complaint email.");
Email email3 = new Email("This is a spam email.");
Email email4 = new Email("This is a new machine request email.");
spamHandler.handleEmail(email1);
spamHandler.handleEmail(email2);
spamHandler.handleEmail(email3);
spamHandler.handleEmail(email4);
}
}
【2】Python代码
# 定义邮件处理器基类
class EmailHandler:
def __init__(self):
self.next_handler = None
def set_next_handler(self, handler):
self.next_handler = handler
def handle_email(self, email):
pass
# 实现垃圾邮件处理器
class SpamHandler(EmailHandler):
def handle_email(self, email):
if "spam" in email.content:
print("Deleted spam email: " + email.content)
elif self.next_handler:
self.next_handler.handle_email(email)
# 实现Fans邮件处理器
class FansHandler(EmailHandler):
def handle_email(self, email):
if "fans" in email.content:
print("Forwarded fans email to CEO: " + email.content)
elif self.next_handler:
self.next_handler.handle_email(email)
# 实现抱怨邮件处理器
class ComplaintHandler(EmailHandler):
def handle_email(self, email):
if "complaint" in email.content:
print("Forwarded complaint email to legal department: " + email.content)
elif self.next_handler:
self.next_handler.handle_email(email)
# 实现新机器请求邮件处理器
class NewMachineRequestHandler(EmailHandler):
def handle_email(self, email):
if "new machine request" in email.content:
print("Forwarded new machine request email to business department: " + email.content)
elif self.next_handler:
self.next_handler.handle_email(email)
# 定义Email类
class Email:
def __init__(self, content):
self.content = content
# 客户端代码
if __name__ == "__main__":
# 创建邮件处理器
spam_handler = SpamHandler()
fans_handler = FansHandler()
complaint_handler = ComplaintHandler()
new_machine_request_handler = NewMachineRequestHandler()
# 构建责任链
spam_handler.set_next_handler(fans_handler)
fans_handler.set_next_handler(complaint_handler)
complaint_handler.set_next_handler(new_machine_request_handler)
# 模拟收到不同类型的邮件并处理
email1 = Email("This is a fans email.")
email2 = Email("This is a complaint email.")
email3 = Email("This is a spam email.")
email4 = Email("This is a new machine request email.")
spam_handler.handle_email(email1)
spam_handler.handle_email(email2)
spam_handler.handle_email(email3)
spam_handler.handle_email(email4)
【八】实战项目中的应用--实现用户购票责任链验证
【1】购票请求验证引入
- 在实际购票业务场景中,用户发起一次购票请求后,购票接口在真正完成创建订单和扣减余票行为前,需要验证当前请求中的参数是否正常请求,或者说是否满足购票情况。
- 购票请求用户传递的参数是否为空
- 比如:车次 ID、乘车人、出发站点、到达站点等。
- 购票请求用户传递的参数是否正确
- 比如:车次 ID 是否存在、出发和到达站点是否存在等。
- 需要购票的车次是否满足乘车人的数量
- 也就是列车对应座位的余量是否充足。
- 乘客是否已购买当前车次,或者乘客是否已购买当天时间冲突的车次。
- ...
【2】思路引入
- java
public TicketPurchaseRespDTO purchaseTickets(PurchaseTicketReqDTO requestParam) {
// 购票请求用户传递的参数是否为空
// 购票请求用户传递的参数是否正确
// 需要购票的车次是否满足乘车人的数量
// 乘客是否已购买当前车次,或者乘客是否已购买当天时间冲突的车次
// ......
}
- python
from typing import Dict, List
class TicketPurchaseRespDTO:
def __init__(self, success: bool, message: str, data: Dict):
self.success = success
self.message = message
self.data = data
...
class TicketPurchaseReqDTO:
def __init__(self, user_id: int, train_id: int, passengers: List[int]):
self.user_id = user_id
self.train_id = train_id
self.passengers = passengers
...
class TicketPurchaseService:
def purchase_tickets(self, request_param: TicketPurchaseReqDTO) -> TicketPurchaseRespDTO:
# 购票请求用户传递的参数是否为空
# 购票请求用户传递的参数是否正确
# 需要购票的车次是否满足乘车人的数量
# 乘客是否已购买当前车次,或者乘客是否已购买当天时间冲突的车次
# 其他购票逻辑处理
# 检查车次容量是否足够
# 检查购票冲突
# ...
...
def main():
purchase_service = TicketPurchaseService()
request_param = TicketPurchaseReqDTO(user_id=1, train_id=123, passengers=[101, 102])
response = purchase_service.purchase_tickets(request_param)
print(f"Purchase Result: {response.success}, Message: {response.message}, Data: {response.data}")
【3】流程及问题
- 解决前置校验需求需要实现一堆逻辑,常常需要写上几百上千行代码。
- 并且,上面的代码不具备开闭原则,以及代码扩展性,整体来说复杂且臃肿。
- 为了避免这种坏代码味道,我们可以运用责任链设计模式,对购票验证逻辑进行抽象。
【4】责任链模式引入
(1)什么是责任链模式
- 在责任链模式中,多个处理器依次处理同一个请求。
- 一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条
- 链条上的每个处理器各自承担各自的处理职责。
(2)责任链模式优点
- 责任链模式的优点在于,它可以动态地添加、删除和调整处理者对象,从而灵活地构建处理链。
- 同时,它也避免了请求发送者和接收者之间的紧耦合,增强了系统的灵活性和可扩展性。
【5】责任链优化项目
(1)定义购票过滤接口
package org.opengoofy.index12306.biz.ticketservice.service.handler.ticket.filter.purchase;
import org.opengoofy.index12306.biz.ticketservice.common.enums.TicketChainMarkEnum;
import org.opengoofy.index12306.biz.ticketservice.dto.req.PurchaseTicketReqDTO;
import org.opengoofy.index12306.framework.starter.designpattern.chain.AbstractChainHandler;
/**
* 列车购买车票过滤器
*/
public interface TrainPurchaseTicketChainFilter<T extends PurchaseTicketReqDTO> extends AbstractChainHandler<PurchaseTicketReqDTO> {
@Override
default String mark() {
return TicketChainMarkEnum.TRAIN_PURCHASE_TICKET_FILTER.name();
}
}
- 这段代码定义了一个购票过滤接口
TrainPurchaseTicketChainFilter
,它继承了AbstractChainHandler
接口,并提供了默认实现方法mark()
,用于返回责任链的标识。 - 这个接口将在不同的购票过滤器中实现。
(2)实现列车购买过滤器实现
/**
* 购票流程过滤器之验证参数必填
*/
@Component
public class TrainPurchaseTicketParamNotNullChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
@Override
public void handler(PurchaseTicketReqDTO requestParam) {
// ......
}
@Override
public int getOrder() {
return 0;
}
}
/**
* 购票流程过滤器之验证参数是否有效
* 验证参数有效这个流程会大量交互缓存,为了优化性能需要使用 Lua。为了方便大家理解流程,这里使用多次调用缓存
*/
@Component
@RequiredArgsConstructor
public class TrainPurchaseTicketParamVerifyChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
private final TrainMapper trainMapper;
private final TrainStationMapper trainStationMapper;
private final DistributedCache distributedCache;
@Override
public void handler(PurchaseTicketReqDTO requestParam) {
// ......
}
@Override
public int getOrder() {
return 10;
}
}
/**
* 购票流程过滤器之验证列车站点库存是否充足
*/
@Component
@RequiredArgsConstructor
public class TrainPurchaseTicketParamStockChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
private final SeatMarginCacheLoader seatMarginCacheLoader;
private final DistributedCache distributedCache;
@Override
public void handler(PurchaseTicketReqDTO requestParam) {
// ......
}
@Override
public int getOrder() {
return 20;
}
}
/**
* 购票流程过滤器之验证乘客是否重复购买
*/
@Component
@RequiredArgsConstructor
public class TrainPurchaseTicketRepeatChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
@Override
public void handler(PurchaseTicketReqDTO requestParam) {
// ......
}
@Override
public int getOrder() {
return 30;
}
}
- 购票过滤器的实现包括了验证参数是否为空、验证参数是否有效、验证列车站点库存是否充足、验证乘客是否重复购买等。
- 每个过滤器实现了
TrainPurchaseTicketChainFilter
接口,并根据自身的业务逻辑实现了handler
方法和getOrder
方法。 - 这些过滤器会在责任链中按照
getOrder
方法返回的值排序执行。
(3)购票流程使用过滤器
private final AbstractChainContext<PurchaseTicketReqDTO> purchaseTicketAbstractChainContext;
@Override
@Transactional(rollbackFor = Throwable.class)
public TicketPurchaseRespDTO purchaseTickets(PurchaseTicketReqDTO requestParam) {
// 责任链模式,验证 0:参数必填 1:参数正确性 2:列车车次余量是否充足 3:乘客是否已买当前车次等
purchaseTicketAbstractChainContext.handler(TicketChainMarkEnum.TRAIN_PURCHASE_TICKET_FILTER.name(), requestParam);
// ......
}
- 购票服务在实际调用时,使用了责任链模式来处理购票请求。
- 首先创建了一个
TicketPurchaseService
的实例,然后通过purchaseTicketAbstractChainContext
调用责任链中的过滤器,传递购票请求参数,并按照责任链的执行顺序依次处理请求。
【6】购票责任链实现原理
(1)运行时获取责任链具体实现类
- 方法位置:org.opengoofy.index12306.biz.ticketservice.service.impl.TicketServiceImpl#purchaseTickets
private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();
/**
* 责任链组件执行
*
* @param mark 责任链组件标识
* @param requestParam 请求参数
*/
public void handler(String mark, T requestParam) {
// 通过 mark 获取到本次需要执行的责任链组件
List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
// 获取为空抛出异常
if (CollectionUtils.isEmpty(abstractChainHandlers)) {
throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
}
// 获取到的责任链组件依次执行
abstractChainHandlers.forEach(each -> each.handler(requestParam));
}
- 责任链模式的实现原理在
AbstractChainContext
类中,它实现了CommandLineRunner
接口,表示在Spring Boot启动完成后执行的回调函数。
(2)初始化责任链容器
// CommandLineRunner:SpringBoot 启动完成后执行的回调函数
public final class AbstractChainContext<T> implements CommandLineRunner {
// 存储责任链组件实现和责任链业务标识的容器
// 比如:Key:购票验证过滤器 Val:HanlderA、HanlderB、HanlderC、......
private final Map<String, List<AbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();
@Override
public void run(String... args) throws Exception {
// 调用 SpirngIOC 工厂获取 AbstractChainHandler 接口类型的 Bean
Map<String, AbstractChainHandler> chainFilterMap = ApplicationContextHolder
.getBeansOfType(AbstractChainHandler.class);
chainFilterMap.forEach((beanName, bean) -> {
// 获取 mark(责任链业务标识)的处理器集合
List<AbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(bean.mark());
// 如果不存在则创建一个集合
if (CollectionUtils.isEmpty(abstractChainHandlers)) {
abstractChainHandlers = new ArrayList();
}
// 添加到处理器集合中
abstractChainHandlers.add(bean);
// 对处理器集合执行顺序进行排序
List<AbstractChainHandler> actualAbstractChainHandlers = abstractChainHandlers.stream()
.sorted(Comparator.comparing(Ordered::getOrder))
.collect(Collectors.toList());
// 存入容器等待被运行时调用
abstractChainHandlerContainer.put(bean.mark(), actualAbstractChainHandlers);
});
}
}
- 在
run
方法中,它通过Spring的IoC容器获取所有实现了AbstractChainHandler
接口的Bean,然后根据它们的mark
方法返回的责任链业务标识将它们分组存储在abstractChainHandlerContainer
容器中。 - 这样,在运行时,可以根据具体的业务标识获取到对应的责任链处理器,并按照它们的
getOrder
方法返回的值排序执行。
【7】Python代码复写项目(伪代码)
from typing import List, Dict
# 定义购票响应DTO
class TicketPurchaseRespDTO:
def __init__(self, success: bool, message: str, data: Dict):
self.success = success
self.message = message
self.data = data
# 定义购票请求DTO
class TicketPurchaseReqDTO:
def __init__(self, user_id: int, train_id: int, passengers: List[int]):
self.user_id = user_id
self.train_id = train_id
self.passengers = passengers
# 定义购票过滤器接口
class TrainPurchaseTicketChainFilter:
def mark(self):
pass
def handler(self, request_param: TicketPurchaseReqDTO):
pass
# 实现列车购买过滤器 - 验证参数必填
class TrainPurchaseTicketParamNotNullChainHandler(TrainPurchaseTicketChainFilter):
def mark(self):
return "TRAIN_PURCHASE_TICKET_FILTER"
def handler(self, request_param: TicketPurchaseReqDTO):
# 验证参数是否为空
if not request_param:
return TicketPurchaseRespDTO(False, "参数为空", None)
# 其他参数验证逻辑
# ......
def getOrder(self):
return 0
# 实现列车购买过滤器 - 验证参数有效性
class TrainPurchaseTicketParamVerifyChainHandler(TrainPurchaseTicketChainFilter):
def __init__(self, train_mapper, train_station_mapper, distributed_cache):
self.train_mapper = train_mapper
self.train_station_mapper = train_station_mapper
self.distributed_cache = distributed_cache
def mark(self):
return "TRAIN_PURCHASE_TICKET_FILTER"
def handler(self, request_param: TicketPurchaseReqDTO):
# 验证参数有效性
# 具体逻辑根据业务需求实现
# ......
...
def getOrder(self):
return 10
# 实现列车购买过滤器 - 验证列车站点库存是否充足
class TrainPurchaseTicketParamStockChainHandler(TrainPurchaseTicketChainFilter):
def __init__(self, seat_margin_cache_loader, distributed_cache):
self.seat_margin_cache_loader = seat_margin_cache_loader
self.distributed_cache = distributed_cache
def mark(self):
return "TRAIN_PURCHASE_TICKET_FILTER"
def handler(self, request_param: TicketPurchaseReqDTO):
# 验证列车站点库存是否充足
# 具体逻辑根据业务需求实现
# ......
...
def getOrder(self):
return 20
# 实现列车购买过滤器 - 验证乘客是否重复购买
class TrainPurchaseTicketRepeatChainHandler(TrainPurchaseTicketChainFilter):
def mark(self):
return "TRAIN_PURCHASE_TICKET_FILTER"
def handler(self, request_param: TicketPurchaseReqDTO):
# 验证乘客是否重复购买
# 具体逻辑根据业务需求实现
# ......
...
def getOrder(self):
return 30
# 责任链模式上下文
class AbstractChainContext:
def __init__(self):
self.handlers = []
def add_handler(self, handler):
self.handlers.append(handler)
def handler(self, request_param: TicketPurchaseReqDTO):
for handler in self.handlers:
result = handler.handler(request_param)
if not result.success:
return result # 停止处理链
def main():
# 创建购票请求参数
request_param = TicketPurchaseReqDTO(user_id=1, train_id=123, passengers=[101, 102])
# 创建责任链上下文
chain_context = AbstractChainContext()
# 添加购票过滤器到责任链上下文
chain_context.add_handler(TrainPurchaseTicketParamNotNullChainHandler())
chain_context.add_handler(TrainPurchaseTicketParamVerifyChainHandler(train_mapper, train_station_mapper, distributed_cache))
chain_context.add_handler(TrainPurchaseTicketParamStockChainHandler(seat_margin_cache_loader, distributed_cache))
chain_context.add_handler(TrainPurchaseTicketRepeatChainHandler())
# 开始责任链处理
response = chain_context.handler(request_param)
# 打印购票响应结果
print(f"Purchase Result: {response.success}, Message: {response.message}, Data: {response.data}")
# 客户端代码示例
if __name__ == "__main__":
main()
标签:HeadFirst,self,购票,public,责任,handler,设计模式,email,def
From: https://www.cnblogs.com/dream-ze/p/17720672.html