使用函数式实现观察者模式模式

栏目: 后端 · 发布时间: 5年前

内容简介:观察者模式肯定是最常见和最广泛使用的模式之一。其目的是允许在某个事件发生时通知一个或多个对象并相应地采取行动。这种模式的主要抽象是Listener接口:当on对象想要在事件发生时得到通知,或者要监听事件时,它只需实现此接口并在onEvent()方法的主体中编码它如何对事件的到达作出反应。对应的是一个Observable对象,或者换句话说,一个对象通过在相关事件发生时向它们发送事件来通知其注册的侦听器。在引入lambdas之前,在这个Observable上注册Listener的两种典型方法是通过匿名内部类:

观察者模式肯定是最常见和最广泛使用的模式之一。其目的是允许在某个事件发生时通知一个或多个对象并相应地采取行动。这种模式的主要抽象是Listener接口:

<b>interface</b> Listener {
    <b>void</b> onEvent(Object event);
}

当on对象想要在事件发生时得到通知,或者要监听事件时,它只需实现此接口并在onEvent()方法的主体中编码它如何对事件的到达作出反应。对应的是一个Observable对象,或者换句话说,一个对象通过在相关事件发生时向它们发送事件来通知其注册的侦听器。

<b>public</b> <b>class</b> Observable {
    <b>private</b> <b>final</b> Map<Object, Listener> listeners = <b>new</b> ConcurrentHashMap<>();
 
    <b>public</b> <b>void</b> register(Object key, Listener listener) {
        listeners.put(key, listener);
    }
 
    <b>public</b> <b>void</b> unregister(Object key) {
        listeners.remove(key);
    }
 
    <b>public</b> <b>void</b> sendEvent(Object event) {
        <b>for</b> (Listener listener : listeners.values()) {
            listener.onEvent( event );
        }
    }
}

在引入lambdas之前,在这个Observable上注册Listener的两种典型方法是通过匿名内部类:

<b>public</b> <b>class</b> Observer1 {
    Observer1(Observable observable) {
        observable.register( <b>this</b>, <b>new</b> Listener() {
            @Override
            <b>public</b> <b>void</b> onEvent( Object event ) {
                System.out.println(event);
            }
        } );
    }
}

或使您的对象直接实现Listener接口。

<b>public</b> <b>class</b> Observer2 implements Listener {
    Observer2(Observable observable) {
        observable.register( <b>this</b>, <b>this</b> );
    }
    @Override
    <b>public</b> <b>void</b> onEvent( Object event ) {
        System.out.println(event);
    }
}

这两个观察者都可以以相同的方式使用,当Observable发送一个事件时,它将被广播到:

Observable observable = <b>new</b> Observable();
<b>new</b> Observer1( observable );
<b>new</b> Observer2( observable );
observable.sendEvent( <font>"Hello World!"</font><font> );
</font>

然而,这两个解决方案再一次揭示了GoF模式最大部分的常见问题:它们必须将动词以及事件到达时要采取的行动转换为名词、类别、匿名或不包装这些行为。为了利用 Java 8的新功能特性,首先要注意的是我们上面定义的Listener接口在语义上等同于Consumer:

<b>public</b> <b>class</b> Observable {
    <b>private</b> <b>final</b> Map<Object, Consumer<Object>> listeners = <b>new</b> ConcurrentHashMap<>();
 
    <b>public</b> <b>void</b> register(Object key, Consumer<Object> listener) {
        listeners.put(key, listener);
    }
 
    <b>public</b> <b>void</b> unregister(Object key) {
        listeners.remove(key);
    }
 
    <b>public</b> <b>void</b> sendEvent(Object event) {
        listeners.values().forEach( listener -> listener.accept( event ) );
    }
}

此外,不再需要使用特定类实现Listener,并且可以使用lambda表达式对事件到达的反应进行编码,或者在这种情况下也使用更简洁的方法引用进行编码。

Observable observable = <b>new</b> Observable();
observable.register( <font>"key1"</font><font>, e -> System.out.println(e) );
observable.register( </font><font>"key2"</font><font>, System.out::println );
observable.sendEvent( </font><font>"Hello World!"</font><font> );
</font>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

迎接互联网的明天

迎接互联网的明天

邹静 / 电子工业 / 2011-6 / 55.00元

《迎接互联网的明天-玩转3D Web(附盘)》,全书共5章,第1章主要阐述了国内外空前繁荣的3D互联网技术领域,以及这些领域透射出来的潜在商机;第2章主要用当下比较流行的Flash编程语言ActionScript 3,来向大家介绍面向对象编程语言的思想概念,以及一些3D渲染技术的入门知识;第3章注重建模知识的运用,主要运用WireFusion和3ds Max来制作3D网页;第4章主要介绍3D游戏编......一起来看看 《迎接互联网的明天》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具