亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java設(shè)計模式之責(zé)任鏈模式的概念、實(shí)現(xiàn)以及netty中的責(zé)任鏈模式

 更新時間:2020年12月20日 08:41:50   作者:易(Master Yi)  
這篇文章主要給大家介紹了關(guān)于設(shè)計模式之責(zé)任鏈模式的概念、實(shí)現(xiàn)以及netty中的責(zé)任鏈模式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

本文先介紹了責(zé)任鏈模式的概念及簡單實(shí)現(xiàn)。再貼了netty中對責(zé)任鏈的實(shí)現(xiàn)。最后總結(jié)了一點(diǎn)點(diǎn)思考。

1、概念相關(guān)

1.1、概念

責(zé)任鏈模式為請求創(chuàng)建了一個接收者對象的鏈,每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,沿著這條鏈傳遞請求,直到有對象處理它為止。

1.2、解決了什么:

客戶只需要將請求發(fā)送到職責(zé)鏈上即可,無須關(guān)心請求的處理細(xì)節(jié)和請求的傳遞,所以職責(zé)鏈將請求的發(fā)送者和請求的處理者解耦了。

1.3、場景:

1、有多個對象可以處理同一個請求,具體哪個對象處理該請求由運(yùn)行時刻自動確定。

2、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。

3、可動態(tài)指定一組對象處理請求。

2、簡單實(shí)現(xiàn)

2.1 代碼

注:代碼中g(shù)etter 和 setter都省略

定義一個請求

public class Request {

 private String name;

 private int days;
 
}

定義一個返回結(jié)果

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;
 }
 // 實(shí)現(xiàn)接口的方法- 獲取請求
 public Request request() {
 return request;
 }
 // 實(shí)現(xiàn)接口的方法- 處理請求
 public Result proceed(Request request) {
 // 取隊(duì)首的處理器開始請求。如果隊(duì)首的處理器處理了,直接返回結(jié)果
 // 如果隊(duì)首的處理器選擇傳遞請求,又會進(jìn)這個proceed方法。取新的隊(duì)首處理
 // 為什么是傳遞而不是直接遍歷隊(duì)列,如果result = null,繼續(xù);result != null,返回呢? 因?yàn)閭鬟f的方式,可以對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("結(jié)果:" + result1.isAgree());

 }
} 

結(jié)果

傳入3:
返回:
C處理了
結(jié)果:true

傳入2:
返回:
B處理了
結(jié)果:true

傳入1:
返回:
A處理了
結(jié)果:true

3. netty中的責(zé)任鏈模式

用過netty的同學(xué)看到下面這個代碼應(yīng)該很熟悉了,非常簡單netty客戶端,創(chuàng)建連接,設(shè)置編解碼器,發(fā)送請求。

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() 應(yīng)該就是一個鏈,持有了channel上所有的處理器。pipeline()方法返回一個ChannelPipeline接口,我們直接看它的實(shí)現(xiàn)類

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);
 // 調(diào)用了 addLast0方法
 addLast0(newCtx);
 ...
 }
 callHandlerAdded0(newCtx);
 return this;
 }

 private void addLast0(AbstractChannelHandlerContext newCtx) {
 // 把新加入的處理器設(shè)置成尾部的前驅(qū),原尾部的前驅(qū)設(shè)置成新處理器的后繼
 AbstractChannelHandlerContext prev = tail.prev;
 newCtx.prev = prev;
 newCtx.next = tail;
 prev.next = newCtx;
 tail.prev = newCtx;
 }
}

通過addLast0, 我們看到DefaultChannelPipeline使用了鏈表的形式存儲了處理器。

繼續(xù)看這個類的其他方法

public class DefaultChannelPipeline implements ChannelPipeline {
 ...
 @Override
 public final Channel channel() {
 return channel;
 }

 @Override
 public final ChannelPipeline fireChannelActive() {
 AbstractChannelHandlerContext.invokeChannelActive(head);
 return this;
 }
 ...
}

返回當(dāng)前的channel,處理channel上的事件。(就類似于我們上面的鏈里面有g(shù)etRequest(),proceed()方法 )

繼續(xù)跟蹤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();
  }
  });
 }
 }
 // 調(diào)用了invokeChannelActive
 
 private void invokeChannelActive() {
 // 判斷是不是要處理
 if (invokeHandler()) {
  try {
  // 處理
  ((ChannelInboundHandler) handler()).channelActive(this);
  } catch (Throwable t) {
  invokeExceptionCaught(t);
  }
 } else {
  // 事件傳遞
  fireChannelActive();
 }
 }
 
 @Override
 public ChannelHandlerContext fireChannelActive() {
 // 執(zhí)行前需要先找到一個合適的處理器 invokeChannelActive
 invokeChannelActive(findContextInbound(MASK_CHANNEL_ACTIVE));
 return this;
 }
 
 private AbstractChannelHandlerContext findContextInbound(int mask) {
 AbstractChannelHandlerContext ctx = this;
 EventExecutor currentExecutor = executor();
 do {
  // 循環(huán),找到一個合適的處理器并返回
  ctx = ctx.next;
 } while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_INBOUND));
 return ctx;
 }
}

其實(shí)看到這,這個鏈已經(jīng)非常的明顯了。 pipline持有處理器,AbstractChannelHandlerContext做了一些封裝,使得鏈上的處理器能對事件進(jìn)行傳遞和處理。

最后再看下handler的實(shí)現(xiàn)類

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
 ......
 @Override
 public void channelActive(ChannelHandlerContext ctx) throws Exception {
 ctx.fireChannelActive();
 }
 ......
}

以這個ChannelInboundHandlerAdapter為例,在channel收到激活事件通知的時候,它調(diào)用了ctx.fireChannelActive();方法傳遞了事件。ctx是ChannelHandlerContext類型,很熟悉,它是個接口,我們上面看到的AbstractChannelHandlerContext是它的實(shí)現(xiàn)類。就這樣,一個激活事件就在鏈上傳遞了起來。而鏈上的處理器就是我們最初始的測試方法里面addLast進(jìn)去的。

4、思考

在netty中,事件在責(zé)任鏈中有序傳播,事件處理器可以處理自己關(guān)心的功能,可以攔截,也可以繼續(xù)傳播(向前或向后)事件。上層的業(yè)務(wù)只需要關(guān)心自己的邏輯。整個架構(gòu)層次分明。

OA系統(tǒng)的工作流 似乎也特別適合責(zé)任鏈模式,正如我們一開始的例子,不同人審批不同的時長的假期。

對于代碼里某些冗長的if else ,是不是也有改造成責(zé)任鏈的可能?

if (通過第一關(guān)) {
    進(jìn)入第二關(guān)
    if (通過第二關(guān)) {
        進(jìn)入第三關(guān)
        ...
    }
}

改成通過第一關(guān)后傳遞事件,反之結(jié)束。這期間還可以靈活的做跳躍,得到某個獎勵,直接跳到第三關(guān)。如果要添加第四關(guān),也比if else靈活的多。

當(dāng)然并不是if else 都適合改造成責(zé)任鏈模式,還是要具體的業(yè)務(wù)及效率上綜合考慮。個人覺得在流程上有順序依賴的,非常適合。

到此這篇關(guān)于Java設(shè)計模式之責(zé)任鏈模式的概念、實(shí)現(xiàn)以及netty中的責(zé)任鏈模式的文章就介紹到這了,更多相關(guān)責(zé)任鏈模式的概念實(shí)現(xiàn)及netty的責(zé)任鏈模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

[1] https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

[2] chabaoo.cn/article/202504.htm

相關(guān)文章

  • 老生常談比較排序之堆排序

    老生常談比較排序之堆排序

    下面小編就為大家?guī)硪黄仙U劚容^排序之堆排序。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Spring Boot2.0整合ES5實(shí)現(xiàn)文章內(nèi)容搜索實(shí)戰(zhàn)

    Spring Boot2.0整合ES5實(shí)現(xiàn)文章內(nèi)容搜索實(shí)戰(zhàn)

    這篇文章主要介紹了Spring Boot2.0整合ES5實(shí)現(xiàn)文章內(nèi)容搜索實(shí)戰(zhàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 詳解Java 序列化與反序列化(Serialization)

    詳解Java 序列化與反序列化(Serialization)

    這篇文章主要介紹了Java 序列化與反序列化(Serialization),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí) 吧
    2019-03-03
  • SpringBoot中支持Https協(xié)議的實(shí)現(xiàn)

    SpringBoot中支持Https協(xié)議的實(shí)現(xiàn)

    本文主要介紹了SpringBoot中支持Https協(xié)議的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Spring多線程通過@Scheduled實(shí)現(xiàn)定時任務(wù)

    Spring多線程通過@Scheduled實(shí)現(xiàn)定時任務(wù)

    這篇文章主要介紹了Spring多線程通過@Scheduled實(shí)現(xiàn)定時任務(wù),@Scheduled?定時任務(wù)調(diào)度注解,是spring定時任務(wù)中最重要的,下文關(guān)于其具體介紹,需要的小伙伴可以參考一下
    2022-05-05
  • Java調(diào)用Shell命令的方法

    Java調(diào)用Shell命令的方法

    這篇文章主要介紹了Java調(diào)用Shell命令的方法,實(shí)例分析了java調(diào)用shell命令的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • 基于Map的computeIfAbsent的使用場景和使用方式

    基于Map的computeIfAbsent的使用場景和使用方式

    這篇文章主要介紹了基于Map的computeIfAbsent的使用場景和使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 使用@CacheEvict清除指定下所有緩存

    使用@CacheEvict清除指定下所有緩存

    這篇文章主要介紹了使用@CacheEvict清除指定下所有緩存,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 深入理解java中的synchronized關(guān)鍵字

    深入理解java中的synchronized關(guān)鍵字

    這篇文章主要介紹了java中的synchronized關(guān)鍵字,有需要的朋友可以參考一下
    2013-12-12
  • Spring注解驅(qū)動擴(kuò)展原理BeanFactoryPostProcessor

    Spring注解驅(qū)動擴(kuò)展原理BeanFactoryPostProcessor

    這篇文章主要介紹了Spring注解驅(qū)動擴(kuò)展原理BeanFactoryPostProcessor,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03

最新評論