【问题标题】:Observer pattern: observe attributes independently观察者模式:独立观察属性
【发布时间】:2020-12-08 12:30:55
【问题描述】:

我想问当我需要实现这样的事情时,我应该如何正确地实现观察者模式:

WeatherStation[temperature, humidity ...]

而且我需要能够独立地“观察”每个属性。因此,当温度变化时,只会通知温度观察者,当湿度变化时,只会通知湿度订阅者。

我的想法是创建一些类,例如 ObservableTemperature 和接口 TemperatureObserver,但这样我就必须为每个属性创建两个“类”。

第二个选项是只为每个属性创建两个接口(例如 TemperatureSource、TemperatureObserver ...),然后在 WeatherStation 类中实现 xxxSource 接口,但这样它不能重用,我需要在 WeatherStation 类中具有许多数组(与“可观察”属性相同的数量)跟踪观察者。

还有更好的选择吗?

编辑: 此外,我也会有类似 Display 类的东西,它会订阅多个属性(不是全部),并且仍然需要区分其中哪一个被更新。

【问题讨论】:

  • 好吧,您可以使用标准/通用类,只需为各个属性注册观察者,或者如果您想让它更安全,请使用泛型,例如ObservableProperty<Temperature>PropertyObserver<Temperature>.
  • 这样我就需要为每种类型创建类,对吗?因为例如如果两个属性是相同的类型(浮点数),我将无法区分它们。附言我认为 Java 中不存在 PropertyObserver<...>,至少我找不到它。
  • 是的,如果您需要属性是类型安全的,您需要为每种类型创建一个类。在大多数情况下,您不需要这样做,只需为不同的属性注册相同观察者接口的实例(例如,类似这样的伪代码getObservable("temperature").register(new Observer&lt;Float&gt;() { ... })。是的,PropertyObserver 可能不存在,但如果你不能使用您也可以自己推出任何现有的类和接口。
  • 这听起来很有趣,如果没有更好的解决方案建议,我可能会走这条路。但是我仍然认为我必须为属性创建这些类,即使我不需要它是类型安全的,因为我无法说出 Observer 何时由温度触发,何时由湿度触发,如果我是对的.
  • 嗯,你通常会在每个属性上注册不同的观察者,所以如果你在“湿度”上触发观察者,你可以假设你得到的是湿度的变化。为了获得更多安全性,您可以查看是否也可以传递属性名称,例如类似于 PropertyChangedEvent("humidity") 来收听或 ObservableProperty("humidity") 来订阅。

标签: java design-patterns observer-pattern


【解决方案1】:

temperaturehumidity 等组合成一个类WeatherStation 定义了一个域概念。就观察者模式而言,这是一个主题。另一方面,发送由单个值组成的通知会将WeatherStation 划分为多个领域概念和多个主题。显然这两个设计决策之间存在冲突。

GoF 模式是根据作为主体的对象(而不是字段)来定义的。但请注意,这并不限制主题在不同时间通知不同观察者。本书的相关部分从第 298 页开始。

明确指定感兴趣的修改。您可以通过扩展主题的注册接口以允许仅针对感兴趣的特定事件注册观察者来提高更新效率。当这样的事件发生时,对象只通知那些对该事件感兴趣的观察者。支持这一点的一种方法是对 Subject 对象使用 aspects 的概念。为了注册对特定事件的兴趣,观察者使用

void Subject::Attach(Observer*, Aspects interest);

其中interest 指定感兴趣的事件。在通知时,主体将更改的方面作为更新操作的参数提供给其观察者。例如:

void Observer::Update(Subject*, Aspect& interest);

这种方法使不同的观察者可以注册来自一个Subject 的不同通知。请注意,无论观察者注册哪个方面,它都会在通知消息中收到相同的Subject。由观察者从Subject 中读取必要的字段。

【讨论】:

  • 非常感谢您的回复!我会检查这本书,这正是我需要但不知道的。
  • 嗨,我不确定我应该如何在 Java 中实现它,我在这里打开了一个关于这个问题的问题。我会使用枚举来表示兴趣,然后我需要在 Observer.update() 中包含 CASE。还有一件事我不明白。如果在书中他们说观察者应该保持对主题的引用并提取数据,为什么更新方法会发送 SUBJECT,更新应该只是这样做的信号。
  • 本书描述了观察者模式的push and pull models。您可以使用任一方法在观察者中获取主题引用。
  • 请注意,我在这里的回答是针对避免为每个属性添加额外的类或数组的问题而量身定制的。通过向现有的主题和观察者添加逻辑,我们可以使用更少的类和集合。这个答案突出了一个权衡。在面向对象的编程中,类的增加是一个特性(不是错误)。添加类和接口意味着您已经识别并标记了更多域。如果是我的项目,我可能会为每个可观察属性添加两个接口和一个集合,而不是尝试最小化类和字段的数量。
  • 感谢您的回复,问题不是“如何避免额外的类或数组?”但这更像是“我为每个属性创建一个观察者界面时可以吗?”。我不确定我是否没有遗漏某些东西,以及是否有更好的方法来做到这一点。实际上我现在已经用很多接口和数组实现了它。
猜你喜欢
  • 1970-01-01
  • 2016-02-20
  • 2023-04-10
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-26
相关资源
最近更新 更多