Java中的通用观察者模式

Java中的通用观察者模式,java,generics,observer-pattern,Java,Generics,Observer Pattern,java.util.Observer和java.util.Observable很难看。它们需要各种类型的强制类型转换,这会让类型安全风扇感到不舒服,并且如果没有丑陋的强制类型转换,您无法将一个类定义为多个事物的观察者。事实上,在“”中,每个观察者/被观察者只能使用一种类型的数据 我试图用Java制作一个观察器模式的通用版本,以解决这两个问题。这与前面提到的帖子没有什么不同,但这个问题没有得到明显解决(最后一条评论是OP中一个未回答的问题)。Observer.java package util;

java.util.Observer
java.util.Observable
很难看。它们需要各种类型的强制类型转换,这会让类型安全风扇感到不舒服,并且如果没有丑陋的强制类型转换,您无法将一个类定义为多个事物的观察者。事实上,在“”中,每个观察者/被观察者只能使用一种类型的数据

我试图用Java制作一个观察器模式的通用版本,以解决这两个问题。这与前面提到的帖子没有什么不同,但这个问题没有得到明显解决(最后一条评论是OP中一个未回答的问题)。

Observer.java

package util;

public interface Observer<ObservedType> {
    public void update(Observable<ObservedType> object, ObservedType data);
}
package-util;
公共接口观察员{
公共无效更新(可观察对象、可观察类型数据);
}
java

package util;

import java.util.LinkedList;
import java.util.List;

public class Observable<ObservedType> {

    private List<Observer<ObservedType>> _observers = 
      new LinkedList<Observer<ObservedType>>();

    public void addObserver(Observer<ObservedType> obs) {
        if (obs == null) {
            throw new IllegalArgumentException("Tried
                      to add a null observer");
        }
        if (_observers.contains(obs)) {
            return;
        }
        _observers.add(obs);
    }

    public void notifyObservers(ObservedType data) {
        for (Observer<ObservedType> obs : _observers) {
            obs.update(this, data);
        }
    }
}
package-util;
导入java.util.LinkedList;
导入java.util.List;
可观测的公共类{
私人名单_观察员=
新建LinkedList();
公共观察员(观察员obs){
如果(obs==null){
抛出新的IllegalArgumentException(“已尝试
添加一个空观察者“);
}
如果(_.contains(obs)){
返回;
}
_新增观察员(obs);
}
公共观察者(观测类型数据){
观察员(obs:_观察员){
obs.更新(此,数据);
}
}
}

希望这对某人有用。

我更喜欢使用注释,以便侦听器可以侦听不同类型的事件

public class BrokerTestMain {
    public static void main(String... args) {
        Broker broker = new Broker();
        broker.add(new Component());

        broker.publish("Hello");
        broker.publish(new Date());
        broker.publish(3.1415);
    }
}

class Component {
    @Subscription
    public void onString(String s) {
        System.out.println("String - " + s);
    }

    @Subscription
    public void onDate(Date d) {
        System.out.println("Date - " + d);
    }

    @Subscription
    public void onDouble(Double d) {
        System.out.println("Double - " + d);
    }
}
印刷品

String - Hello
Date - Tue Nov 13 15:01:09 GMT 2012
Double - 3.1415

@Target(ElementType.METHOD)
@保留(RetentionPolicy.RUNTIME)
公共@接口订阅{
}
公共类经纪人{
私有最终映射=新LinkedHashMap();
公共无效添加(对象o){
对于(方法:o.getClass().getMethods()){
类[]parameterTypes=method.getParameterTypes();
如果(method.getAnnotation(Subscription.class)==null | | parameterTypes.length!=1)继续;
类subscribeTo=参数类型[0];
List subscriberInfo=map.get(subscribeTo);
if(subscriberInfo==null)
put(subscribeTo,subscriberInfo=newArrayList());
添加(新的SubscriberInfo(方法,o));
}
}
删除公共空间(对象o){
对于(列表订阅信息:map.values()){
对于(int i=subscriberInfo.size()-1;i>=0;i--)
if(subscriberInfo.get(i).object==o)
订阅信息。删除(i);
}
}
公共int发布(对象o){
List subscriberInfo=map.get(o.getClass());
if(subscriberInfo==null)返回0;
整数计数=0;
for(SubscriberInfo SubscriberInfo:SubscriberInfo){
subscriberInfo.invoke(o);
计数++;
}
返回计数;
}
静态类SubscriberInfo{
最终方法;
最终目标;
SubscriberInfo(方法,对象){
这个方法=方法;
this.object=对象;
}
无效调用(对象o){
试一试{
调用(对象,o);
}捕获(例外e){
抛出新断言错误(e);
}
}
}
}

我曾经使用编写了一个Java观察器模式的通用实现。以下是如何使用它的示例:

Gru gru = new Gru();
Minion fred = new Minion();
fred.addObserver(gru);
fred.moo();

public interface IMinionListener
{
    public void laughing(Minion minion);
}

public class Minion extends AbstractObservable<IMinionListener>
{
    public void moo()
    {
        getEventDispatcher().laughing(this);
    }
}

public class Gru implements IMinionListener
{
    public void punch(Minion minion) { ... }

    public void laughing(Minion minion)
    {
        punch(minion);
    }
}
Gru-Gru=new Gru();
仆从弗雷德=新仆从();
弗雷德·阿德观察者(gru);
弗雷德。穆奥();
公共接口IMinionListener
{
公众虚空大笑(奴才奴才);
}
公共类仆从扩展了AbstractObservable
{
公屋
{
getEventDispatcher()。笑(这个);
}
}
公共类Gru实现IMinionListener
{
公共无效穿孔(仆从仆从){…}
公众虚空大笑(奴才奴才)
{
打孔(仆从);
}
}
这个。回溯我,也指相关项目


,并将动态代理方法与其他方法进行了对比。当然非常感谢。我还没有签出,但它可能只是包含;至少它看起来是一个成熟的库。

尝试使用Guava的类EventBus

您可以这样声明观察者:

    public class EventObserver {
        @Subscribe 
        public void onMessage(Message message) {
            ...
        }
    }
EventBus eventBus = new EventBus();
eventBus.register(new EventObserver());
新的事件总线如下所示:

    public class EventObserver {
        @Subscribe 
        public void onMessage(Message message) {
            ...
        }
    }
EventBus eventBus = new EventBus();
eventBus.register(new EventObserver());
然后像这样注册观察者:

    public class EventObserver {
        @Subscribe 
        public void onMessage(Message message) {
            ...
        }
    }
EventBus eventBus = new EventBus();
eventBus.register(new EventObserver());
最后通知观察员如下:

eventBus.post(message);

现代更新:是一个非常好的API,用于基于观察者模式的异步编程,并且是完全通用的。如果您使用Observer/Observable将数据或事件从代码中的一个位置“流”到另一个位置,那么您肯定应该仔细研究它

它基于函数式编程,因此使用Java 8的lambda语法看起来非常流畅:

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
        .reduce((x, y) -> x + y)
        .map((v) -> "DecoratedValue: " + v)
        .subscribe(System.out::println);

我发现了一个类似的请求,但它是在codereview上。 我认为在这里值得一提

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Supplier;

/**
 * like java.util.Observable, But uses generics to avoid need for a cast.
 *
 * For any un-documented variable, parameter or method, see java.util.Observable
 */
public class Observable<T> {

    public interface Observer<U> {
        public void update(Observable<? extends U> observer, U arg);
    }

    private boolean changed = false;
    private final Collection<Observer<? super T>> observers;

    public Observable() {
        this(ArrayList::new);
    }

    public Observable(Supplier<Collection<Observer<? super T>>> supplier) {
        observers = supplier.get();
    }

    public void addObserver(final Observer<? super T> observer) {
        synchronized (observers) {
            if (!observers.contains(observer)) {
                observers.add(observer);
            }
        }
    }

    public void removeObserver(final Observer<? super T> observer) {
        synchronized (observers) {
            observers.remove(observer);
        }
    }

    public void clearObservers() {
        synchronized (observers) {
            this.observers.clear();
        }
    }

    public void setChanged() {
        synchronized (observers) {
            this.changed = true;
        }
    }

    public void clearChanged() {
        synchronized (observers) {
            this.changed = false;
        }
    }

    public boolean hasChanged() {
        synchronized (observers) {
            return this.changed;
        }
    }

    public int countObservers() {
        synchronized (observers) {
            return observers.size();
        }
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(final T value) {
        ArrayList<Observer<? super T>> toNotify = null;
        synchronized(observers) {
            if (!changed) {
                return;
            }
            toNotify = new ArrayList<>(observers);
            changed = false;
        }
        for (Observer<? super T> observer : toNotify) {
            observer.update(this, value);
        }
    }
}
import java.util.ArrayList;
导入java.util.Collection;
导入java.util.function.Supplier;
/**
*与java.util.Observable类似,但使用泛型来避免强制转换。
*
*有关任何未记录的变量、参数或方法,请参见java.util.Observable
*/
可观测的公共类{
公共接口观察员{

public void update(observed)如果(!contains){return;}你为什么要做
if(!contains){return;}那么add()
当你可以简单地做
if(contains){add();}
的时候。此外,你应该在
IllegalArgumentException
中添加一些文本,猜测你的意思是
if(contains)
if(!contains)
第二轮。因为我更喜欢这种风格,这就是一切。这没有什么区别。而且,是的,我会用充实的文本编辑答案作为例外。完美…轰!!我想我们最好用集合代替列表来处理唯一性。这绝对是一个简洁的解决方案,但对我来说,基于
的界面感觉像是一个很好的解决方案对代码意图的描述。有兴趣知道你的想法。我希望你回答,我认为是g