- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我没有 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
公开为公共(public)来破坏正确的封装。我看不到解决办法,也许我的整个模式都是错误的。我想要一些想法。
还有一个相关的问题:我希望在引发事件的方法返回后立即引发事件。有没有办法使用线程或其他构造来同步它?当然,调用者代码不能参与同步任务。它必须对它完全透明。
最佳答案
这里最好的做法是避免首先实现您自己的事件框架,而是依赖一些现有的库。开箱即用的 Java 提供 EventListener
,并且至少您可以遵循那里记录的模式。即使对于非 GUI 应用程序,大多数建议也适用。
超越 JDK Guava提供了几种可能的选项,具体取决于您的具体用例。
最有可能的候选者是 EventBus
,其中:
allows publish-subscribe-style communication between components without requiring the components to explicitly register with one another (and thus be aware of each other).
或者ListenableFuture
(和ListeningExecutorService)其中:
allows you to register callbacks to be executed once [a task submitted to an
Executor
] is complete, or if the computation is already complete, immediately. This simple addition makes it possible to efficiently support many operations that the basic Future interface cannot support.
或者Service
API 其中:
represents an object with an operational state, with methods to start and stop. For example, webservers, RPC servers, and timers can implement the Service interface. Managing the state of services like these, which require proper startup and shutdown management, can be nontrivial, especially if multiple threads or scheduling is involved.
此 API 同样可以让您 register listeners响应您的服务中的状态变化。
即使这些选项都不直接适合您的用例,请查看 Guava's source code有关事件驱动行为和监听器的示例,您可以尝试模拟。
关于java - 如何在java中创建某种事件框架?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38948557/
我是一名优秀的程序员,十分优秀!