• 关于过滤器,拦截器,监听器


    链接:https://www.zhihu.com/question/35225845

    过滤器(Filter):

    过滤器换一种表达就是预处理(pre processing)或者后处理(post processing),你说到的依赖于servlet容器,我觉得这是狭隘层次上的定义,你用米进行煮饭前要做什么,要用水先对米进行清洗,浸泡一下,这就是预处理;你榨完果汁后是直接喝吗,不,还要用筛子将果渣过滤掉,这就是后处理,对数据进行预处理或者后处理就是过滤器要做的工作,常见的应用有将请求中的数据进行转码,日志系统,系统缓存这些都是要依赖过滤器来实现,servlet中通过实现servlet中给的接口从而实现自定义过滤器,当有多个过滤器时就形成了过滤器链,也就是要依次经过过滤器链中的过滤器才能最终到达实际目标.

    拦截器(Interceptor):

    顾名思义,就是对数据进行拦截,从这个定义上看,似乎和过滤器很像,但是拦截器要做的工作更多是安全方面,比如用户验证,判断是否登陆。和过滤器的一个区别就是拦截器不一定会到达目标,也就是他可以拒绝你的请求,但是过滤器是一定会到达目标,但是在到达目标前或者后要进行一些操作.

    监听器:

    显然就是生活中的监视,和监听相关的概念就是事件,这些名词在生活中其实都经常接触。事件往大了说就是动作的序列,往小了说就是一个动作。想想电影中某个大boss叫你去监视某个人,那么你就充当了监听器的作用,监视的作用意义何在,就是当被监视对象出现了某个状态时要做出处理(触发某个方法),一般大boss会对你说如果那个人作出了什么举动(出现了某个状态),那么你就怎么怎么样,你监视的对象的动作或者说状态就是所谓的事件,而你(监听器)对这个状态的处理就是处理方法。举javascript中的例子来说,鼠标点击事件(onClick一个动作),键盘按下事件(onKeyDown,onKeyPress一个动作)等,显然javascript给相应对象设置了监听器。



    过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。
    拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。
    监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。

    ======================================


    更形象一点表示:

    过滤器:只想要在一堆东西里面选个B

    拦截:水流变小点,把鱼都拦住!顺便发个电

    监听器:题主一定会说上面是个水利工程,其实发电的原理是这样的。。

    ======================================

    设计模式的命名都跟真实的场景有密切相关性,只要理解了命名,就理解了模式。题主在网上搜到的东西都是关于模式在Struts中的具体实现,虽然它们的确都在Struts中很常用,然而然而跟action、反射没有半毛钱关系,甚至跟Java都没有关系。不过显然题主对Java比较熟悉,碰巧我也比较熟悉Java,那不妨以Java举例:

    Filter:
    // 填充100个带有随机字母标签的球
    List<String> array = new ArrayList<>();
    Random r = new Random();
    String[] balls = new String[]{"A", "B", "C"};
    for (int i = 0; i < 100; i++)
      array.add(balls[r.nextInt(3)]);
    
    // 只拿出B的来。不明白的自行学习Java 8
    array = array.stream().filter(ball -> ball.equals("B")).collect(Collectors.toList());
    

    Interceptor:
    class River {
      // 流量
      int volume;
    
      // 总鱼数
      int numFish;
    }
    
    class PowerGenerator {
      double generate (int volume) {
        // 假设每一百立方米水发一度电
        return volume / 100;
      }
    }
    
    interface Interceptor {
      void intercept (River river);
    }
    
    class SomeInterceptor implements Interceptor {
      PowerGenerator generator = new PowerGenerator();
    
      @Override
      public void intercept (River river) {
        // 消耗了1000立方米水来发电
        int waterUsed = 1000;
    
        // 水量减少了1000。请不要跟我讨论水电站原理的问题,
        // 我就那么一比方
        river.volume -= waterUsed;
    
        // 发电
        generator.generate (waterUsed);
    
        // 拦截所有的鱼
        river.numFish = 0;
      }
    }
    
    class RiverController {
      Interceptor interceptor;
    
      void flow(River river) {
        // 源头积累下来的水量和鱼
        river.volume += 100000
        river.numFish += 1000
    
        // 经过了大坝
        interceptor.intercept(river);
    
        // 下了点雨
        river.volume += 1000
      }
    
      void setInterceptor (Interceptor interceptor) {
        this.interceptor = interceptor
      }
    }
    
    class Main {
      public static void main (String args[]) {
        RiverController rc = new RiverController;
        Interceptor inter = new SomeInterceptor();
    
        // 这一步通常叫做控制反转或依赖注入,其实也没啥子
        rc.setInterceptor(inter);
    
        rc.flow(new River());
      }
    }
    

    Listener:
    // 监听器
    interface BedListener {
      // 监听器在参数中收到了某个事件,而这个事件往往是只读的
      // 监听器的方法名通常以"on"开头
      void onBedSound (String sound);
    }
    
    class Neighbor {
      BedListener listener;
    
      // 依然是所谓控制反转
      setListener (BedListener listener) {
        this.listener = listener;
      }
    
      void doInterestingStuff () {
        // 根据当地法律法规,部分内容无法显示
    
        // 将事件发送给监听器
        listener.onBedSound("嘿咻");
        listener.onBedSound("oyeah");
      }
    }
    
    class Main {
      public static void main (String args[]) {
        Neighbor n = new Neighbor();
        n.setListener (sound -> generatePower());
        n.doInterestingStuff();
      }
    
      private static void generatePower() {
        // 根据当地法律法规,部分内容无法显示
      }
    }
    

    ======================================


    在真实使用中,很多人,不管是新手还是老手会犯的一个错误是,在不该改变对象状态的时候强制改变它,或者在应该传入只读参数时传入了可变参数。

    上面的例子中,Filter的例子是JDK提供的函数,如果你在这里改变了对象的状态(当然例子里的String类型本来就不可以改变),就违背了filter的约定。

    同样的,在Listener中不管是传入了可变的对象,或是对该对象进行了修改,都是违背设计模式约定的做法,会给其他读代码的人造成困扰。

    而Interceptor几乎可以对流程做任何事情,所以没有什么特别要注意的地方,用这一类接口的时候仔细读文档,设计这一类接口的时候仔细写文档吧。

    三幅大图系无节操手绘,凑和着看吧。
  • 相关阅读:
    SSAS : 如何在http访问SSAS中指定语言标识
    网络开发:在Socket中发送大文件
    CSS应用及其优先级问题
    SSAS : 使用.NET为SSAS编写自定义程序集
    SSAS : 如何编写自定义挖掘算法
    什么是高清视频
    SSAS : 使用.NET为SSAS编写自定义程序集(二)
    循证架构寻找最适合自己的架构
    有道难题,我的OO解法
    假如我是海洋
  • 原文地址:https://www.cnblogs.com/mike-mei/p/8082252.html
Copyright © 2020-2023  润新知