设计模式-责任链模式(Chain of Responsibility Pattern)
一、定义
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
二、概念解释
链就是链路,比如有一个员工请假流程的审批,低效的方式就是员工写好假条,按顺序分别找小组领导、部门领导、公司老板去签字,很显然这种方式很拉跨,员工写好请假条只找自己的上级签字,上级签完后再去找上级的上级,员工就避免了和多个接受者的耦合关系,就比较优雅,定义里提到了有机会处理,用员工的例子理解就是视员工请假时间长短来决定要处理到哪一级别。
三、场景
我们玩过很多抽卡游戏,很多游戏会鼓励你抽卡做一些激励活动,比如抽多少次送A级英雄,抽多少次送S级英雄这种来刺激你消费,这里我们就可以使用责任链模式来实现这样一种机制
四、实现
1、类图
2、代码实现
定义一个抽象的奖励处理类 该抽象类有一个自身类型的变量并提供一个奖励英雄卡片的方法,比较重要的就是定义的这个自身类型的变量,它是构成链的关键
@AllArgsConstructor
public abstract class RewardHandler {
private final RewardHandler next;
public void rewardHero(RequestCards requestCards) {
if (Objects.nonNull(next)) {
next.rewardHero(requestCards);
}
}
}
定义该抽象类的实现类,调用父类有参构造方法初始化子类对象
// 二十抽奖励类
public class DrawingTwentyTimesHandler extends RewardHandler{
public DrawingTwentyTimesHandler(RewardHandler rewardHandler) {
super(rewardHandler);
}
@Override
public void rewardHero(RequestCards requestCards) {
if (requestCards.getCardDrawingTimes() >= 20) {
System.out.println("抽卡次数已满二十,奖励A级英雄一个,加把劲抽够50,再给你个S级英雄");
super.rewardHero(requestCards);
}else {
System.out.println("零氪玩家");
}
}
}
// 五十抽奖励类
public class DrawingFiftyTimesHandler extends RewardHandler{
public DrawingFiftyTimesHandler(RewardHandler rewardHandler) {
super(rewardHandler);
}
@Override
public void rewardHero(RequestCards requestCards) {
if (requestCards.getCardDrawingTimes() >= 50) {
System.out.println("抽奖次数已满50,奖励S级英雄一个,加把劲抽够100再给你个SS级英雄");
super.rewardHero(requestCards);
}else {
System.out.println("轻氪用户,稍微关注");
}
}
}
// 一百抽奖励类
public class DrawingHundredTimesHandler extends RewardHandler{
public DrawingHundredTimesHandler(RewardHandler rewardHandler) {
super(rewardHandler);
}
@Override
public void rewardHero(RequestCards requestCards) {
if (requestCards.getCardDrawingTimes() >= 100) {
System.out.println("抽奖次数已满100,奖励SS级英雄一个,这波不亏(*^_^*)");
}else {
System.out.println("氪金大佬,重点关注");
}
}
}
封装抽卡请求这个对象
@Data
@AllArgsConstructor
public class RequestCards {
/**
* 抽卡次数
*/
private Integer cardDrawingTimes;
}
定义一个抽卡的玩家
public class LeekPlayer {
private RewardHandler chain;
public LeekPlayer() {
buildChain();
}
// 通过该方法初始化一个抽卡次数的奖励链
private void buildChain() {
chain = new DrawingTwentyTimesHandler(new DrawingFiftyTimesHandler(new DrawingHundredTimesHandler(null)));
}
// 根据初始化的奖励链对象执行奖励机制
public void DrawCardsUntilNoMoney(RequestCards requestCards) {
chain.rewardHero(requestCards);
}
}
谁也劝不了我,我要开抽了
@SpringBootTest
public class ChainOfResponsibilityTest {
@Test
public void test() {
// 玩家 准备大抽一波 把奖励拉满
LeekPlayer leekPlayer = new LeekPlayer();
// 直接100抽
RequestCards requestCards = new RequestCards(100);
// 开抽
leekPlayer.DrawCardsUntilNoMoney(requestCards);
}
}
五、总结
优点:
- 如定义所言,解耦,发送者和接收者不用一一接触,通过链来处理请求
- 方便扩展,针对本文,后续如果出现60抽80抽奖励等,直接新增两个类,修改构造的链条即可
缺点:
- 如果写爽了可能会构造出一个长度可观的链条出来,对性能是会有较大的影响,所以用的时候注意限制该链条长度
- 如果有bug,不太好调试,增加了定位问题的复杂度