您好,登录后才能下订单哦!
这期内容当中小编将会给大家带来有关怎么在Java项目中实现一个责任链模式,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
1、概念相关
责任链模式为请求创建了一个接收者对象的链,每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,沿着这条链传递请求,直到有对象处理它为止。
客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3、可动态指定一组对象处理请求。
注:代码中getter 和 setter都省略
定义一个请求
public class Request { private String name; private int days; }
定义一个返回结果
public class Result { private boolean agree; public Result(boolean agree) { this.agree = agree; } }
定义一个处理接口
public interface Handler { // 每个处理器持有链,能取到链上的请求或者传递请求 Result deal(Chain chain); interface Chain { // 获取请求 Request request(); // 传递请求 Result proceed(Request request); } }
定义一个处理接口的链
public class HandlerChain implements Handler.Chain { // 持有链要处理的请求 private Request request; // 持有链上所有的处理器 private Queue<Handler> handlers; public HandlerChain(Request request) { this.request = request; } // 添加一个处理器 public HandlerChain addHandler(Handler handler) { if (handlers == null) { handlers = new LinkedList<>(); } handlers.add(handler); return this; } // 实现接口的方法- 获取请求 public Request request() { return request; } // 实现接口的方法- 处理请求 public Result proceed(Request request) { // 取队首的处理器开始请求。如果队首的处理器处理了,直接返回结果 // 如果队首的处理器选择传递请求,又会进这个proceed方法。取新的队首处理 // 为什么是传递而不是直接遍历队列,如果result = null,继续;result != null,返回呢? 因为传递的方式,可以对request再次处理。A处理器可以做简单处理,再传递给B。 Handler handler = handlers.poll(); return handler.deal(this); } }
定义三个处理者
public class AHandler implements Handler{ public Result deal(Chain chain) { Request request = chain.request(); // 只处理小于等于1的请求,大于1的请求被传递了 if (request.getDays() > 1) { // 这里可以对request做部分处理,再传递 return chain.proceed(request); } System.out.println("A处理了"); return new Result(true); } } public class BHandler implements Handler { public Result deal(Chain chain) { Request request = chain.request(); // 只处理小于等于2的请求,大于2的请求被传递了 if (request.getDays() > 2) { return chain.proceed(request); } System.out.println("B处理了"); return new Result(true); } } public class CHandler implements Handler { public Result deal(Chain chain) { Request request = chain.request(); // 只处理小于等于3的请求,大于3的请求被传递了 if (request.getDays() > 3) { return chain.proceed(request); } System.out.println("C处理了"); return new Result(true); } }
测试
public class Test { public static void main(String[] args) { // new 一个链,往链上添加处理器 Request request1 = new Request("hhy", 3); HandlerChain chains = new HandlerChain(request1).addHandler(new AHandler()).addHandler(new BHandler()).addHandler(new CHandler()); Result result1 = chains.proceed(request1); System.out.println("结果:" + result1.isAgree()); } }
结果
传入3:
返回:
C处理了
结果:true传入2:
返回:
B处理了
结果:true传入1:
返回:
A处理了
结果:true
用过netty的同学看到下面这个代码应该很熟悉了,非常简单netty客户端,创建连接,设置编解码器,发送请求。
public static void main(String[] args) { EventLoopGroup group = new NioEventLoopGroup(); NioSocketChannel channel = new NioSocketChannel(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).option(ChannelOption.TCP_NODELAY, true); InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(httpRequest.host), httpRequest.port); group.register(channel); channel.connect(address).sync(); channel.pipeline().addLast("http-decoder", new HttpResponseDecoder()); channel.pipeline().addLast("http-encoder", new HttpRequestEncoder()); channel.pipeline().addLast("http-client", new HttpHandler(HttpClient.this)); channel.writeAndFlush(httpRequest); }
通过我们上面的例子,不难猜测到 channel.pipeline() 应该就是一个链,持有了channel上所有的处理器。pipeline()方法返回一个ChannelPipeline接口,我们直接看它的实现类
public class DefaultChannelPipeline implements ChannelPipeline { final AbstractChannelHandlerContext head; final AbstractChannelHandlerContext tail; @Override public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) { final AbstractChannelHandlerContext newCtx; synchronized (this) { checkMultiplicity(handler); // 把handler封装成AbstractChannelHandlerContext newCtx = newContext(group, filterName(name, handler), handler); // 调用了 addLast0方法 addLast0(newCtx); ... } callHandlerAdded0(newCtx); return this; } private void addLast0(AbstractChannelHandlerContext newCtx) { // 把新加入的处理器设置成尾部的前驱,原尾部的前驱设置成新处理器的后继 AbstractChannelHandlerContext prev = tail.prev; newCtx.prev = prev; newCtx.next = tail; prev.next = newCtx; tail.prev = newCtx; } }
通过addLast0, 我们看到DefaultChannelPipeline使用了链表的形式存储了处理器。
继续看这个类的其他方法
public class DefaultChannelPipeline implements ChannelPipeline { ... @Override public final Channel channel() { return channel; } @Override public final ChannelPipeline fireChannelActive() { AbstractChannelHandlerContext.invokeChannelActive(head); return this; } ... }
返回当前的channel,处理channel上的事件。(就类似于我们上面的链里面有getRequest(),proceed()方法 )
继续跟踪invokeChannelActive方法
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint { static void invokeChannelActive(final AbstractChannelHandlerContext next) { EventExecutor executor = next.executor(); if (executor.inEventLoop()) { next.invokeChannelActive(); } else { executor.execute(new Runnable() { @Override public void run() { next.invokeChannelActive(); } }); } } // 调用了invokeChannelActive private void invokeChannelActive() { // 判断是不是要处理 if (invokeHandler()) { try { // 处理 ((ChannelInboundHandler) handler()).channelActive(this); } catch (Throwable t) { invokeExceptionCaught(t); } } else { // 事件传递 fireChannelActive(); } } @Override public ChannelHandlerContext fireChannelActive() { // 执行前需要先找到一个合适的处理器 invokeChannelActive invokeChannelActive(findContextInbound(MASK_CHANNEL_ACTIVE)); return this; } private AbstractChannelHandlerContext findContextInbound(int mask) { AbstractChannelHandlerContext ctx = this; EventExecutor currentExecutor = executor(); do { // 循环,找到一个合适的处理器并返回 ctx = ctx.next; } while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_INBOUND)); return ctx; } }
其实看到这,这个链已经非常的明显了。 pipline持有处理器,AbstractChannelHandlerContext做了一些封装,使得链上的处理器能对事件进行传递和处理。
最后再看下handler的实现类
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler { ...... @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelActive(); } ...... }
以这个ChannelInboundHandlerAdapter为例,在channel收到激活事件通知的时候,它调用了ctx.fireChannelActive();方法传递了事件。ctx是ChannelHandlerContext类型,很熟悉,它是个接口,我们上面看到的AbstractChannelHandlerContext是它的实现类。就这样,一个激活事件就在链上传递了起来。而链上的处理器就是我们最初始的测试方法里面addLast进去的。
在netty中,事件在责任链中有序传播,事件处理器可以处理自己关心的功能,可以拦截,也可以继续传播(向前或向后)事件。上层的业务只需要关心自己的逻辑。整个架构层次分明。
OA系统的工作流 似乎也特别适合责任链模式,正如我们一开始的例子,不同人审批不同的时长的假期。
对于代码里某些冗长的if else ,是不是也有改造成责任链的可能?
if (通过第一关) {
进入第二关
if (通过第二关) {
进入第三关
...
}
}
改成通过第一关后传递事件,反之结束。这期间还可以灵活的做跳跃,得到某个奖励,直接跳到第三关。如果要添加第四关,也比if else灵活的多。
上述就是小编为大家分享的怎么在Java项目中实现一个责任链模式了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。