我有一个简单的类 - 将其称为Animal。我想在Animal类中触发一个事件,并在我实例化Animal类的类中处理它。在事件处理程序中,我想传递一个Integer值
如何实现这样简单的事情?
答案 0 :(得分:21)
假设传递的整数是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);
}
}
}
最后,我建议不要使用Observer
/ Observable
,因为它会使代码难以理解/难以理解:您经常需要检查传递的参数的类型在向下转换之前使用Observer
到instanceof
,并且通过查看其接口定义很难看出特定Observer实现期望的事件类型。更好地定义特定的侦听器实现和事件以避免这种情况。
答案 1 :(得分:9)
如果要避免从类似java.util.Observable的基类继承,请使用接口并让您的observable实现或委托接口的方法。
这是可观察的界面:
public interface IObservable
{
void addObserver(IObserver o);
void deleteObserver(IObserver o);
void notifyObservers(INotification notification);
}
这是一个可以由你的真正的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);
}
}
}
真实的观察者看起来像这样:
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;
}
}
这是观察者界面:
public interface IObserver
{
void update(INotification notification);
}
最后,这是通知界面和基本实现:
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;
}
}
答案 2 :(得分:5)
简单的事件界面如下所示:
public interface AnimalListener {
public void animalDoesSomething(int action);
}
Animal
需要管理其听众:
public class Animal {
private final List<AnimalListener> animalListeners = new ArrayList<AnimalListener>()
public void addAnimalListener(AnimalListener animalListener) {
animalListeners.add(animalListener);
}
}
您的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!");
}
}
现在Animal
可以触发事件。
public class Animal {
....
public void doSomething() {
for (AnimalListener animalListener : animalListeners) {
animalListener.animalDoesSomething(4);
}
}
}
对于像“触发事件”这样简单的事情看起来像很多代码但是可能触发事件并不简单。 :)
当然,这种简单机制有各种扩展。
java.util.EventListener
。public void animalDoesSomething(Animal animal, int action);
。答案 3 :(得分:3)
PropertyChangeSupport
的方法似乎更好观察我建议的方法。
答案 4 :(得分:3)
我相信他们所有人的最简单的解决方案已经错过了一点......
在95%的情况下,你不需要超过这个:
public class Aminal extends Observable {
public void doSomethingThatNotifiesObservers() {
setChanged();
notifyObservers(new Integer(42));
}
}
我猜你没有自动装箱,所以我制作了一个Integer
对象,但部分来自于此,Observable
类来自JDK1.0,所以它应该出现在你的Java版本。
使用自动装箱(在Java 1.5及更高版本中),notifyObservers
调用将如下所示:
notifyObservers(42);
为了捕获已发送的事件,您需要实现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
}
}
}
然后您将GetInt
添加到Animal
类:
Animal animal = new Animal();
GetInt getint = new GetInt();
animal.addObserver(getint);
这是所有标准Java,Observable
类实现了您需要的所有观察者处理。
如果您需要能够从外部触发Observable
,请使用Steve McLeod的解决方案,但根据我的经验,您将希望让您的班级处理它所知道的内容并让其他课程通过Observer
接口。
您唯一需要注意的是,您需要在setChanged()
之前致电notifyObservers()
,否则Observable
将不会发送任何事件。
我认为这样你可以调用几个setChanged()
,然后只通知观察者一次,让他们知道课程已经改变,并让他们知道如何。
一旦不再需要创建它的类,移除观察者也是一种很好的形式,这样可以防止观察者留在观察者中。只是垃圾收集观察者类不会将其从可观察对象中删除。
如果您想按照每个属性观察课程,我建议您按照上面Adamski所述的PropertyChangeSupport
进行操作。如果您希望侦听器能够阻止更改,还可以使用VetoableChangeSupport
。
答案 5 :(得分:2)
Observer / Observable类从第1天就开始使用Java。不幸的是,最初的设计师在某种程度上搞砸了。公平地说,他们没有机会学习10年的Java经验......
我用委托来解决你的问题。我有自己的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 {
}
答案 6 :(得分:1)
我在这里的第一个建议是看看AspectJ。这是该语言最适合处理的设计模式之一。以下文章提供了如何实现这一点的非常有说服力的描述:
http://www.ibm.com/developerworks/java/library/j-aopwork6/index.html
答案 7 :(得分:0)
还有伟大的 Spring 库,提供开箱即用的事件框架。
答案 8 :(得分:0)
Guava的EventBus是另一种现成的选择