我在这里问,只有当对象的特定属性发生变化时,我才需要通知观察者时,我应该如何处理这种情况。
我收到了关于GoF的非常好的回复,其中写道:
区块报价明确指定感兴趣的修改。您可以通过扩展受试者的注册界面来提高更新效率,只允许为感兴趣的特定事件注册观察员。当此类事件发生时,受试者只通知那些对该事件感兴趣的观察者。支持这一点的一种方法是使用Subject对象的方面概念。为了记录对特定事件的兴趣,观察员使用与他们的受试者联系
void Subject::Attach(Observer*, Aspects interest);
区块报价其中感兴趣指定感兴趣的事件。在通知时,主题将更改后的方面作为更新操作的参数提供给其观察者。例如:
void Observer::Update(Subject*, Aspect& interest);
这是有道理的,我想问一下如何在Java中正确地实现这一点。我几乎没有什么想法,但我不确定是否还有更好的办法。
让我们想象一下,我有受试者类别WeatherStation[temperature, humidity, windSpeed ...]
和观测者类LimitedDisplay[show (shows only temperature and humidity)
,出于某种原因,我需要显示器能够区分何时只改变温度和何时只改变湿度。
我想我可以创建一些枚举WeatherStationInterest[TEMPERATURE, HUMIDITY WIND_SPEED...]
,然后有这样的主题界面:
public interface WeatherStationSubject{
registerObserver(WeatherStationObserver observer, WeatherStationInterest... interests);
.
.
.
}
有人能向我确认这是正确的方法吗?或者建议我更好的解决方案。
另一个选项是拥有一组接口:
interface TemperatureListener {
onTemperatureChange(double newTemperature);
}
interface HumidityListener {
onHumidityChange(double newHumidity);
}
...
然后注册方法看起来像:
void registerListener(Object listener)
你可以实现一个监听器:
class MyListener implements TemperatureListener, HumidityListener {
...
}
不一定更好,但如果这很重要的话,可以很容易地看到实际发生了什么变化。
这是一个具有单个观察者接口和多个通知的实现。正如在上一个问题中所评论的,我并不特别喜欢这个解决方案,因为我更喜欢用单独的接口命名观察者,而不是发送方法参数;但这表明了用更少的类换取更多的逻辑的折衷。
public class Main {
enum ObservableValue {
TEMP, HUMIDITY, WIND
}
interface Observer {
void notify(ObservableValue changed);
}
static class LimitedDisplay implements Observer {
@Override
public void notify(ObservableValue changed) {
System.out.println(changed + " has changed.");
}
}
static class WeatherStation {
private double temp;
private double humidity;
private double wind;
private final Map<ObservableValue, Set<Observer>> observers = new EnumMap<>(ObservableValue.class);
WeatherStation() {
Arrays.stream(ObservableValue.values()).forEach(value -> observers.put(value, new HashSet<>()));
}
void register(Observer observer, ObservableValue... values) {
Arrays.stream(values).forEach(value -> observers.get(value).add(observer));
}
void setTemp(double temp) {
this.temp = temp;
observers.get(TEMP).forEach(observer -> observer.notify(TEMP));
}
void setHumidity(double humidity) {
this.humidity = humidity;
observers.get(HUMIDITY).forEach(observer -> observer.notify(HUMIDITY));
}
void setWind(double wind) {
this.wind = wind;
observers.get(WIND).forEach(observer -> observer.notify(WIND));
}
}
public static void main(String[] args) {
WeatherStation ws = new WeatherStation();
ws.register(new LimitedDisplay(), ObservableValue.values());
ws.setTemp(1.2);
ws.setHumidity(3.4);
ws.setWind(5.6);
}
}