如何在 Java 中声明和使用事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1553010/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to declare and consume events in Java
提问by AngryHacker
I have a simple class - will call it Animal. I'd like to fire off an event in the Animal class and have it handled in the class where I instantiated the Animal class. In the event handler, I want to pass an Integer value
我有一个简单的类 - 将其称为 Animal。我想在 Animal 类中触发一个事件,并在我实例化 Animal 类的类中处理它。在事件处理程序中,我想传递一个整数值
How do I pull off something simple like that?
我如何完成这样简单的事情?
采纳答案by Frank Grimm
When you want to avoid inheriting from a java.util.Observable-like base class, use an interface and let your observables implement or delegate the interface's methods.
当您想避免从类似 java.util.Observable 的基类继承时,请使用接口并让您的 observable 实现或委托接口的方法。
Here is the observable interface:
这是可观察的接口:
public interface IObservable
{
void addObserver(IObserver o);
void deleteObserver(IObserver o);
void notifyObservers(INotification notification);
}
Here is a helper class that could be used by your real observables:
这是一个可以被你的真实观察者使用的辅助类:
import java.util.ArrayList;
import java.util.List;
public class Observable implements IObservable
{
private List<IObserver> observers;
@Override
public synchronized void addObserver(IObserver o)
{
if (observers == null)
{
observers = new ArrayList<IObserver>();
}
else if (observers.contains(o))
{
return;
}
observers.add(o);
}
@Override
public synchronized void deleteObserver(IObserver o)
{
if (observers == null)
{
return;
}
int idx = observers.indexOf(o);
if (idx != -1)
{
observers.remove(idx);
}
}
@Override
public synchronized void notifyObservers(INotification notification)
{
if (observers == null)
{
return;
}
for (IObserver o : observers)
{
o.update(notification);
}
}
}
A real observable could look like this:
一个真正的 observable 可能是这样的:
class Person implements IObservable
{
private final IObservable observable = new Observable();
@Override
public void setFirstName(String firstName) throws Exception
{
if (firstName == null || firstName.isEmpty())
{
throw new Exception("First name not set");
}
this.firstName = firstName;
notifyObservers(new Notification(this, getFirstNamePropertyId()));
}
@Override
public void addObserver(IObserver o)
{
observable.addObserver(o);
}
@Override
public void deleteObserver(IObserver o)
{
observable.deleteObserver(o);
}
@Override
public void notifyObservers(INotification notification)
{
observable.notifyObservers(notification);
}
private static final String FIRSTNAME_PROPERTY_ID = "Person.FirstName";
@Override
public String getFirstNamePropertyId()
{
return FIRSTNAME_PROPERTY_ID;
}
}
Here is the observer interface:
这是观察者界面:
public interface IObserver
{
void update(INotification notification);
}
Finally, here is the notification interface and a basic implementation:
最后,这里是通知接口和基本实现:
public interface INotification
{
Object getObject();
Object getPropertyId();
}
public class Notification implements INotification
{
private final Object object;
private final Object propertyId;
public Notification(Object object, Object propertyId)
{
this.object = object;
this.propertyId = propertyId;
}
@Override
public Object getObject()
{
return object;
}
@Override
public Object getPropertyId()
{
return propertyId;
}
}
回答by Adamski
Assuming that the integer being passed is part of the Animal class state, an idiomatic way to do this rather than writing lots of your own codeis to fire a PropertyChangeEvent. You can use the PropertyChangeSupportclass to do this, reducing your code to this:
假设传递的整数是 Animal 类状态的一部分,这样做而不是编写大量自己的代码的惯用方法是触发PropertyChangeEvent. 您可以使用PropertyChangeSupport该类来执行此操作,将您的代码简化为:
public class Animal {
// Create PropertyChangeSupport to manage listeners and fire events.
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
private int foo;
// Provide delegating methods to add / remove listeners to / from the support class.
public void addPropertyChangeListener(PropertyChangeListener l) {
support.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
support.removePropertyChangeListener(l);
}
// Simple example of how to fire an event when the value of 'foo' is changed.
protected void setFoo(int foo) {
if (this.foo != foo) {
// Remember previous value, assign new value and then fire event.
int oldFoo = this.foo;
this.foo = foo;
support.firePropertyChange("foo", oldFoo, this.foo);
}
}
}
Finally, I would advise against using Observer/ Observableas it makes code unreadable / difficult to follow: You are constantly having to check the type of the argument passed to the Observerusing instanceofbefore downcasting it, and it's difficult to see what type of event a specific Observer implementation is expecting by looking at its interface definition. Much nicer to define specific listener implementations and events to avoid this.
最后,我建议不要使用Observer/Observable因为它使代码不可读/难以遵循:在向下转换之前,您必须不断检查传递给Observerusing的参数的类型instanceof,并且很难看到特定 Observer 实现的事件类型通过查看其接口定义来期待。更好地定义特定的侦听器实现和事件以避免这种情况。
回答by Bombe
A simple event interface looks like this:
一个简单的事件接口如下所示:
public interface AnimalListener {
public void animalDoesSomething(int action);
}
Animalneeds to manage its listeners:
Animal需要管理它的听众:
public class Animal {
private final List<AnimalListener> animalListeners = new ArrayList<AnimalListener>()
public void addAnimalListener(AnimalListener animalListener) {
animalListeners.add(animalListener);
}
}
Your Animal-creating class needs to do this:
你的Animal创建类需要这样做:
public class AnimalCreator implements AnimalListener {
public void createAnimal() {
Animal animal = new Animal();
animal.addAnimalListener(this); // implement addListener in An
}
public void animalDoesSomething(int action) {
System.ot.println("Holy crap, animal did something!");
}
}
Now Animalcan fire events.
现在Animal可以触发事件。
public class Animal {
....
public void doSomething() {
for (AnimalListener animalListener : animalListeners) {
animalListener.animalDoesSomething(4);
}
}
}
That looks like a lot of code for something as simple as “firing events” but maybe firing events isn't simple at all. :)
看起来像“触发事件”这样简单的代码有很多,但可能触发事件根本不简单。:)
Of course there are various extensions to this simple mechanism.
当然,这个简单的机制有各种扩展。
- I always make my event listeners extend
java.util.EventListener. - The first parameter for each listener method should be the source of the event, i.e.
public void animalDoesSomething(Animal animal, int action);. - Management of registered listeners and event firing can be abstracted to some kind of abstract event listener management class. Look at PropertyChangeSupportto know what I mean.
- 我总是让我的事件侦听器扩展
java.util.EventListener。 - 每个侦听器方法的第一个参数应该是事件的来源,即
public void animalDoesSomething(Animal animal, int action);. - 注册监听器和事件触发的管理可以抽象为某种抽象事件监听器管理类。查看PropertyChangeSupport了解我的意思。
回答by Miserable Variable
EDIT: Adamski's PropertyChangeSupportbased approach seems better Observable one that I suggested.
编辑:PropertyChangeSupport基于Adamski 的方法似乎是我建议的更好的 Observable 方法。
回答by Erk
I believe the simplest solution of them all has been missed a bit...
我相信他们中最简单的解决方案已经被遗漏了一点......
You would not need more than this in 95% of the cases:
在 95% 的情况下,您不需要更多:
public class Aminal extends Observable {
public void doSomethingThatNotifiesObservers() {
setChanged();
notifyObservers(new Integer(42));
}
}
I'm guessing you'll have no auto boxing, so I made an Integerobject, but part from that, the Observableclass is from JDK1.0 so it should be present in your version of Java.
我猜你不会有自动装箱,所以我做了一个Integer对象,但其中的一部分,这个Observable类来自 JDK1.0,所以它应该存在于你的 Java 版本中。
With autoboxing (in Java 1.5 and later) the notifyObserverscall would look like this:
使用自动装箱(在 Java 1.5 及更高版本中),notifyObservers调用将如下所示:
notifyObservers(42);
In order to catch the sent event you need to implement the Observerinterface:
为了捕获发送的事件,您需要实现Observer接口:
public class GetInt implements Observer {
@Override
public void update(Observable o, Object arg) {
if (arg instanceof Integer) {
Integer integer = (Integer)arg;
// do something with integer
}
}
}
Then you'll add GetIntto the Animalclass:
然后你将添加GetInt到Animal类中:
Animal animal = new Animal();
GetInt getint = new GetInt();
animal.addObserver(getint);
This is all standard Java and the Observableclass implements all the observer handling you need.
这是所有标准的 Java,Observable该类实现了您需要的所有观察者处理。
If you need to be able to trigger Observablefrom outside, go with Steve McLeod's solution, but in my experience you'll want to let your class handle what it knows and let other classes interact with it via the Observerinterfaces.
如果您需要能够Observable从外部触发,请使用 Steve McLeod 的解决方案,但根据我的经验,您会希望让您的类处理它所知道的内容,并让其他类通过Observer接口与之交互。
The only thing you need to be aware of is that you need to call setChanged()before notifyObservers()or Observablewon't send any events.
您唯一需要注意的是,您需要在setChanged()之前调用notifyObservers()或Observable不会发送任何事件。
I think this is so you can call several setChanged()and then notify the observers only once, letting them know the class has changed and leaving it up to them to figure out how.
我认为这样你就可以调用几个setChanged(),然后只通知观察者一次,让他们知道班级已经改变,让他们来弄清楚如何改变。
It is also good form to remove the observer once the class where it was created is no longer needed, this to prevent the observer from being left in the observable. Just garbage collecting the observer class will not remove it from the observable.
一旦不再需要创建观察者的类,移除观察者也是一种很好的形式,这可以防止观察者留在可观察对象中。只是垃圾收集观察者类不会将其从可观察对象中删除。
If you want to observe the class on a per property basis I'd recommend going with PropertyChangeSupportas described by Adamski above. There's also a VetoableChangeSupportthat you can use if you want listeners to be able to block a change.
如果你想在每个属性的基础上观察类,我建议PropertyChangeSupport按照上面 Adamski 的描述进行。还有一个VetoableChangeSupport,如果你想听众能够阻止一个变化,您可以使用。
回答by Steve McLeod
The Observer/Observable classes have been in Java since day 1. Unfortunately the original designers screwed up somewhat. To be fair, they didn't have the chance to learn from 10 years of Java experience...
Observer/Observable 类从第一天起就在 Java 中出现。不幸的是,最初的设计者有些搞砸了。公平地说,他们没有机会从 10 年的 Java 经验中学习......
I solve your problem with delegation. I have my own implementation of Observer/Observable - and I recommend this. But here's an approach that works:
我用委托解决了你的问题。我有自己的 Observer/Observable 实现 - 我推荐这个。但这是一种有效的方法:
import java.util.Observable;
import java.util.Observer;
public class Animal {
private final ImprovedObservable observable = new ImprovedObservable();
public void addObserver(Observer o) {
observable.addObserver(o);
}
public void notifyObservers() {
observable.notifyObservers();
}
public void doSomething() {
observable.setChanged();
observable.notifyObservers(new AnimalEvent());
}
}
// simply make setChanged public, and therefore usable in delegation
class ImprovedObservable extends Observable {
@Override
public void setChanged() {
super.setChanged();
}
}
class AnimalEvent {
}
回答by Andrew Eisenberg
My first suggestion here would be to look at AspectJ. This is one of the design patterns that the language is best at handling. The following article provides a very eloquent description of how this can be implemented:
我在这里的第一个建议是查看 AspectJ。这是该语言最擅长处理的设计模式之一。以下文章非常雄辩地描述了如何实现:
http://www.ibm.com/developerworks/java/library/j-aopwork6/index.html
http://www.ibm.com/developerworks/java/library/j-aopwork6/index.html
回答by KLE
There is also the great Springlibraries, that provide out-of-the-box an event framework.
还有很棒的Spring库,它们提供开箱即用的事件框架。

