原文: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几乎可以对流程做任何事情,所以没有什么特别要注意的地方,用这一类接口的时候仔细读文档,设计这一类接口的时候仔细写文档吧。
来源:知乎
原文地址:https://www.cnblogs.com/wkcode/p/9608267.html
时间: 2024-10-19 19:39:55