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

栏目: 后端 · 发布时间: 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>

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

查看所有标签

猜你喜欢:

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

XML Hacks

XML Hacks

Michael Fitzgerald / O'Reilly Media, Inc. / 2004-07-27 / USD 24.95

Developers and system administrators alike are uncovering the true power of XML, the Extensible Markup Language that enables data to be sent over the Internet from one computer platform to another or ......一起来看看 《XML Hacks》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

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

正则表达式在线测试