如何在java中创建某种事件框架?

时间:2016-08-15 02:31:01

标签: java events method-reference

我没有GUI(我的类是Minecraft Mod的一部分)。我希望能够模仿C#事件框架:一个类声明事件并让其他人订阅它们。

我的第一个方法是创建一个名为EventArgs的类,然后执行以下操作:

public class EventArgs
{
    public boolean handled;
}

@FunctionalInterface
public interface IEventHandler<TEvtArgs extends EventArgs>
{
    public void handle(Object source, TEvtArgs args);
}

public class Event<TEvtArgs extends EventArgs>
{
    private final Object owner;
    private final LinkedList<IEventHandler<TEvtArgs>> handlers = new LinkedList<>();

    public Event(Object owner)
    {
        this.owner = owner;
    }

    public void subscribe(IEventHandler<TEvtArgs> handler)
    {
        handlers.add(handler);
    }

    public void unsubscribe(IEventHandler<TEvtArgs> handler)
    {
        while(handlers.remove(handler));
    }

    public void raise(TEvtArgs args)
    {
        for(IEventHandler<TEvtArgs> handler : handlers)
        {
            handler.handle(owner, args);
            if(args.handled)
                break;
        }
    }
}

然后一个班级会做这样的事情:

public class PropertyChangedEvtArgs extends EventArgs
{
    public final Object oldValue;
    public final Object newValue;

    public PropertyChangedEvtArgs(final Object oldValue, final Object newValue)
    {
        this.oldValue = oldValue;
        this.newValue = newValue;
    }
}

public class SomeEventPublisher
{
    private int property = 0;
    private final Random rnd = new Random();
    public final Event<PropertyChangedEvtArgs> PropertyChanged = new Event<>(this);

    public void raiseEventOrNot(int value)
    {
        if(rnd.nextBoolean())//just to represent the fact that the event is not always raised
        {
            int old = property;
            property = value;
            PropertyChanged.raise(new PropertyChangedEvtArgs("old(" + old + ")", "new(" + value + ")"));
        }                
    }
}

public class SomeSubscriber
{
    private final SomeEventPublisher eventPublisher = new SomeEventPublisher();

    public SomeSubscriber()
    {
        eventPublisher.PropertyChanged.subscribe(this::handlePropertyAChanges);
    }

    private void handlePropertyAChanges(Object source, PropertyChangedEvtArgs args)
    {
        System.out.println("old:" + args.oldValue);
        System.out.println("new:" + args.newValue + "\n");
    }

    public void someMethod(int i)
    {
        eventPublisher.raiseEventOrNot(i);
    }
}

public class Main
{
    private static final SomeSubscriber subscriber = new SomeSubscriber();

    public static void main(String[] args)
    {
        for(int i = 0; i < 10; ++i)
        {
            subscriber.someMethod(i);
        }
    }
}

这种天真的方法最大的问题是它通过公开raise来破坏正确的封装。我无法看到它的方法,也许我的整个模式是错误的。我想要一些想法。

还有一个相关的问题:我希望在之后立即引发事件提升它们的方法返回。有没有办法使用线程或其他构造同步这个?当然,调用者代码不能参与同步任务。它必须完全透明。

0 个答案:

没有答案