过滤器拦截器监听器

Posted wkcode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了过滤器拦截器监听器相关的知识,希望对你有一定的参考价值。

原文:https://www.zhihu.com/question/35225845/answer/61876681

从设计模式的角度分析它们的不同。

过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。

拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。

监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。

 


 

 

更形象一点表示:

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

技术分享图片

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

技术分享图片

 

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

技术分享图片

 

 


 

 

设计模式的命名都跟真实的场景有密切相关性,只要理解了命名,就理解了模式。

不妨以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几乎可以对流程做任何事情,所以没有什么特别要注意的地方,用这一类接口的时候仔细读文档,设计这一类接口的时候仔细写文档吧。

 

来源:知乎

以上是关于过滤器拦截器监听器的主要内容,如果未能解决你的问题,请参考以下文章

web篇过滤器拦截器监听器

web篇过滤器拦截器监听器

过滤器,拦截器,监听器的区别

过滤器,拦截器,监听器的区别

过滤器,拦截器,监听器的区别

过滤器,监听器,拦截器