当前位置: 首页 > news >正文

责任链模式的两种实现

实现一:servlet 经典模式

图片描述

该模式特点:多线程环境环境下,需要每一个客户端请求,new 一个ConcreteFilterChain对象。如果对象太大,增加cpu和gc的负担。

代码demo

import java.io.IOException;

public interface Filter {
    public void doFilter(Context ctx, FilterChain chain) throws IOException;

}
import java.io.IOException;

public interface FilterChain {
    void doFilter(Context ctx) throws IOException;

}
import java.io.IOException;

public class PrintOne implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws IOException {
        System.out.println(Thread.currentThread().getId()+ " 1");
        chain.doFilter(ctx);
    }


}

import java.io.IOException;

public class PrintTwo implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws IOException {

        System.out.println(Thread.currentThread().getId()+" 2");
        chain.doFilter(ctx);
    }
}


import java.io.IOException;

public class PrintThree implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws IOException {

        System.out.println(Thread.currentThread().getId()+" 3");
        chain.doFilter(ctx);
    }
}
import java.io.IOException;
import java.util.List;

public class DefaultFilterChain implements FilterChain {

    public DefaultFilterChain(List<Filter> list) {
        this.list = list;
    }

    List<Filter> list;
    int pos = 0;

    @Override
    public void doFilter(Context ctx) throws IOException {
        if(pos < list.size()){
            Filter filter = list.get(pos);
            pos++;

            filter.doFilter(ctx,this);

        }
    }
}

测试程序

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestMain {
    static ExecutorService executorService = Executors.newFixedThreadPool(5);

    public static void main(String args[]){
        List<Filter> list = new ArrayList<Filter>();
        list.add(new PrintOne());
        list.add(new PrintTwo());
        list.add(new PrintThree());


        FilterChain filterChain = new DefaultFilterChain(list);

        for(int i=0;i<2;i++) {
            executorService.submit(new Event(filterChain));
        }
    }

    public static class Event implements Runnable{
        public Event(FilterChain filterChain) {
            this.filterChain = filterChain;
        }

        FilterChain filterChain;

        @Override
        public void run() {
            Context ctx = new Context();

            try {

                filterChain.doFilter(ctx);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

注意:该测试程序是有bug的,多线程共享filterChain会导致filter的游标定位错误。要解决这个问题,要么每个请求new一个DefaultFilterChain对象。

实现二

参考netty pipeline的实现
图片描述

该实现的优点:多线程环境下,不需要每一个客户的请求都new一个DefaultFilterChain.该算法的巧妙之处在于:将handler跟filterchain 组成成一个节点。 通过handler驱动节点的扭转

上代码

public class Context {
}

public interface Handler {
    void handle(Context ctx,FilterChain filterChain);
}


public class PrintOne implements Handler {
    @Override
    public void handle(Context ctx, FilterChain filterChain) {
        System.out.println(Thread.currentThread().getId()+" 1");

        filterChain.fireNext(ctx);
    }
}


public class PrintTwo implements Handler{
    @Override
    public void handle(Context ctx, FilterChain filterChain) {
        System.out.println(Thread.currentThread().getId()+" 2");

        filterChain.fireNext(ctx);


    }
}


public class PrintThree implements Handler {
    @Override
    public void handle(Context ctx, FilterChain filterChain) {
        System.out.println(Thread.currentThread().getId()+" 3");

        filterChain.fireNext(ctx);

    }
}

FilterChain和DefaultFilterChain

public interface FilterChain {
    void handler(Context ctx);

    void fireNext(Context ctx);
}

public class DefaultFilterChain implements FilterChain {
    private FilterChain next;
    private Handler handler;

    public DefaultFilterChain(FilterChain next, Handler handler) {
        this.next = next;
        this.handler = handler;
    }


    @Override
    public void handler(Context ctx) {
        handler.handle(ctx,this);
    }

    public void fireNext(Context ctx){
        FilterChain next_ = this.next;
        if(next_ != null){
            next_ .handler(ctx);
        }

    }
}

测试代码

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FilterChainTest {
    static ExecutorService executorService = Executors.newFixedThreadPool(3);

    public static void main(String args[]){

        Handler h1 = new PrintOne();
        Handler h2 = new PrintTwo();
        Handler h3 = new PrintThree();

        FilterChain filterChain3 = new DefaultFilterChain(null,h3);
        FilterChain filterChain2 = new DefaultFilterChain(filterChain3,h2);
        FilterChain filterChain1 = new DefaultFilterChain(filterChain2,h1);
        Context ctx = new Context();

        for(int i=0;i<3;i++){
            executorService.execute(new RunPrintEcho(filterChain1,ctx));
        }

    }

    public static class RunPrintEcho implements Runnable{
        FilterChain filterChain;
        Context ctx;

        public RunPrintEcho(FilterChain filterChain, Context ctx) {
            this.filterChain = filterChain;
            this.ctx = ctx;
        }

        @Override
        public void run() {
            filterChain.handler(this.ctx);
        }
    }
}

大功告成!

相关文章:

  • eclipse 导入自定义jar包
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • Appach 服务器如让IP绑定多个域名
  • 三种方法,刷新 Android 的 MediaStore!让你保存的图片立即出现在相册里!
  • Autocomplete 跨域
  • Remember that adversity is not a dead-end but a detour to a better outcome
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • ubuntu触摸板失效问题
  • Maven多模块,Dubbo分布式服务框架,SpringMVC,前后端分离项目,基础搭建,搭建过程出现的问题...
  • Access数据库LIKE问题
  • 系列文章--WCF后传学习文章
  • 多线程(二)
  • [原]Java程序员的JavaScript学习笔记(4——闭包/getter/setter)
  • Dijkstra算法
  • 几种不错的编程字体
  • Angular 2 DI - IoC DI - 1
  • Fastjson的基本使用方法大全
  • input实现文字超出省略号功能
  • JAVA SE 6 GC调优笔记
  • k个最大的数及变种小结
  • Laravel核心解读--Facades
  • PaddlePaddle-GitHub的正确打开姿势
  • tweak 支持第三方库
  • Vue官网教程学习过程中值得记录的一些事情
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 分布式熔断降级平台aegis
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 猫头鹰的深夜翻译:JDK9 NotNullOrElse方法
  • linux 淘宝开源监控工具tsar
  • #include
  • #laravel 通过手动安装依赖PHPExcel#
  • #QT(一种朴素的计算器实现方法)
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (LeetCode 49)Anagrams
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (二)pulsar安装在独立的docker中,python测试
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (六)Hibernate的二级缓存
  • (正则)提取页面里的img标签
  • (转)EOS中账户、钱包和密钥的关系
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net反混淆脱壳工具de4dot的使用
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • .net中生成excel后调整宽度
  • .Net组件程序设计之线程、并发管理(一)
  • :O)修改linux硬件时间
  • [@Controller]4 详解@ModelAttribute
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [20170728]oracle保留字.txt
  • [BT]BUUCTF刷题第9天(3.27)
  • [C#] 我的log4net使用手册
  • [cocos creator]EditBox,editing-return事件,清空输入框
  • [elastic 8.x]java客户端连接elasticsearch与操作索引与文档