文章目录
责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
当一个大的流程有很多步骤时,可以将些步骤链接起来 形成一个责任链,如果符合条件那么调用下一个链,如果不符合条件 那么跳过所有链。
一、责任链如何设计
1、定义责任链处理对象
每个链需要处理的逻辑,有一个统一的方法,这样便于统一调用,可以继承一个公共的抽象类
1.1、抽象类
java
public abstract class AbstractHandler {
/**
* 下一关用当前抽象类来接收
*/
protected AbstractHandler next;
public void setNext(AbstractHandler next) {
this.next = next;
}
public abstract int handler();
}
1.2、责任链处理对象
java
public class FirstPassHandler extends AbstractHandler {
private int play(){
return 80;
}
@Override
public int handler(){
System.out.println("第一关-->FirstPassHandler");
int score = play();
if(score >= 80){
//分数>=80 并且存在下一关才进入下一关
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
java
public class SecondPassHandler extends AbstractHandler {
private int play(){
return 90;
}
public int handler(){
System.out.println("第二关-->SecondPassHandler");
int score = play();
if(score >= 90){
//分数>=90 并且存在下一关才进入下一关
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
2、将"每个链"组合起来,定一个枚举
2.1、枚举对象
java
public enum GatewayEnum {
// handlerId, 拦截者名称,全限定类名,preHandlerId,nextHandlerId
FIRST_HANDLER(new GatewayEntity(1, "api接口限流", "gateway.handler.FirstPassHandler", null, 2)),
SECOND_HANDLER(new GatewayEntity(2, "黑名单拦截", "gateway.handler.SecondPassHandler", 1, null)),
/*如果要 新增第三个责任链,则 再定一个枚举值,将 上一个枚举的 nextId 定义成 第新增的Id*/
/*SESSION_HANDLER(new GatewayEntity(3, "用户会话拦截", "cn.dgut.design.chain_of_responsibility.GateWay.impl.SessionGatewayHandler", 2, null)),*/
;
GatewayEntity gatewayEntity;
public GatewayEntity getGatewayEntity() {
return gatewayEntity;
}
GatewayEnum(GatewayEntity gatewayEntity) {
this.gatewayEntity = gatewayEntity;
}
}
2.2、责任链对象
java
@Setter
@Getter
public class GatewayEntity {
private String name;
private String conference;
private Integer handlerId;
private Integer preHandlerId;
private Integer nextHandlerId;
public GatewayEntity(Integer handlerId,String name,String conference,Integer preId,Integer nextId){
this.handlerId = handlerId;
this.name = name;
this.conference = conference;
this.preHandlerId = preId;
this.nextHandlerId = nextId;
}
}
3、调用时,如何获取责任链对象
如果要调用这个责任链,那么肯定要将这些独立的"链" 链接起来,并获取第一个责任链对象,然后就可以调用了
3.1、获取责任链对象方法
java
public interface GatewayDao {
/**
* 根据 handlerId 获取配置项
* @param handlerId
* @return
*/
GatewayEntity getGatewayEntity(Integer handlerId);
/**
* 获取第一个处理者
* @return
*/
GatewayEntity getFirstGatewayEntity();
}
java
public class GatewayImpl implements GatewayDao {
/**
* 初始化,将枚举中配置的handler初始化到map中,方便获取
*/
private static Map<Integer, GatewayEntity> gatewayEntityMap = new HashMap<>();
static {
GatewayEnum[] values = GatewayEnum.values();
for (GatewayEnum value : values) {
GatewayEntity gatewayEntity = value.getGatewayEntity();
gatewayEntityMap.put(gatewayEntity.getHandlerId(), gatewayEntity);
}
}
@Override
public GatewayEntity getGatewayEntity(Integer handlerId) {
return gatewayEntityMap.get(handlerId);
}
@Override
public GatewayEntity getFirstGatewayEntity() {
for (Map.Entry<Integer, GatewayEntity> entry : gatewayEntityMap.entrySet()) {
GatewayEntity value = entry.getValue();
// 没有上一个handler的就是第一个
if (value.getPreHandlerId() == null) {
return value;
}
}
return null;
}
}
3.2、责任链工厂方法--将这些独立的"链"链接起来,构成责任链,并返回第一个责任链接
java
public class GatewayHandlerEnumFactory {
private static GatewayDao gatewayDao = new GatewayImpl();
// 提供静态方法,获取第一个handler
/**
* 设置 责任链 并返回第第一天 责任链
* @return
*/
public static AbstractHandler getFirstGatewayHandler() {
GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity();
AbstractHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity);
if (firstGatewayHandler == null) {
return null;
}
GatewayEntity tempGatewayEntity = firstGatewayEntity;
Integer nextHandlerId = null;
AbstractHandler tempGatewayHandler = firstGatewayHandler;
// 迭代遍历所有handler,以及将它们链接起来
while ((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null) {
GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId);
AbstractHandler gatewayHandler = newGatewayHandler(gatewayEntity);
tempGatewayHandler.setNext(gatewayHandler);
tempGatewayHandler = gatewayHandler;
tempGatewayEntity = gatewayEntity;
}
// 返回第一个handler
return firstGatewayHandler;
}
/**
* 反射实体化具体的处理者
* @param firstGatewayEntity
* @return
*/
private static AbstractHandler newGatewayHandler(GatewayEntity firstGatewayEntity) {
// 获取全限定类名
String className = firstGatewayEntity.getConference();
try {
// 根据全限定类名,加载并初始化该类,即会初始化该类的静态段
Class<?> clazz = Class.forName(className);
return (AbstractHandler) clazz.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return null;
}
}
4、调用
java
public class GetewayClient {
public static void main(String[] args) {
AbstractHandler firstGetewayHandler = GatewayHandlerEnumFactory.getFirstGatewayHandler();
firstGetewayHandler.handler();
}
}