我应该使用监听器还是观察器?
Posted
技术标签:
【中文标题】我应该使用监听器还是观察器?【英文标题】:Should I use a Listener or Observer? 【发布时间】:2010-10-19 04:31:34 【问题描述】:我的 GUI 中有一个下拉框,它显示另一个类中的 ArrayList 的内容。 新对象可以在 GUI 的其他地方添加到 ArrayList,所以我需要知道它什么时候更新,所以我可以刷新下拉菜单。据我所知,我的两个选择是扩展 ArrayList 类以允许我向其中添加自己的 changeListener,或者使包含相关 ArrayList 的类扩展可观察。
哪个是更合适的解决方案?
【问题讨论】:
你指的是JComboBox吗?如果是这样,我会研究 ComboBoxModel 及其实现。 【参考方案1】:Java 中的Observable
实现很少使用,并且不能与 Swing 很好地互操作。请改用EventListener
。
特别是,在“GUI 的其他位置”管理列表的内容时,是否有理由不扩展AbstractListModel
甚至直接使用DefaultListModel
?然后你的组合框可以使用一个ComboBoxModel
,它代表同一个ListModel
实例,添加它自己的实现来跟踪选择状态。
我有这样的想法(但我没有测试过):
final class MyComboBoxModel
extends AbstractListModel
implements ComboBoxModel
private final ListModel data;
private volatile Object selection;
MyComboBoxModel(ListModel data)
/*
* Construct this object with a reference to your list,
* which contents are managed somewhere else in the UI.
*/
this.data = data;
data.addListDataListener(new ListDataListener()
public void contentsChanged(ListDataEvent evt)
fireContentsChanged(this, evt.getIndex0(), evt.getIndex1());
public void intervalAdded(ListDataEvent evt)
fireContentsChanged(this, evt.getIndex0(), evt.getIndex1());
public void intervalRemoved(ListDataEvent evt)
fireContentsChanged(this, evt.getIndex0(), evt.getIndex1());
);
public void setSelectedItem(Object selection)
this.selection = selection;
fireContentsChanged(this, 0, data.getSize() - 1);
public Object getSelectedItem() return selection;
public int getSize() return data.getSize();
public Object getElementAt(int idx) return data.getElementAt(idx);
【讨论】:
【参考方案2】:这两种解决方案本质上是相同根设计模式(由四人组定义的“观察者”模式)的实现。在前一种情况下,您正在使 ArrayList 本身“可观察”,在后一种情况下,您是使使用数组列表的域对象“可观察”。
我倾向于做后者:使域对象可观察。这主要是因为您最终可能会更改域对象的其他内容(应为其更新 GUI。)如果它已经是可观察的,那么您已经设置好了。
请注意,您不必严格扩展 java.util.Observable
- 您可以在不这样做的情况下实现设计模式。
【讨论】:
这似乎是最简单的方法,不过感谢所有其他答案。【参考方案3】:总是更喜欢组合而不是扩展(我的参考是有效的 java 和我的个人经验)。扩展 ArrayList 只是一个承诺,您不会违反任何类不变量。它还将您绑定到您正在扩展的特定列表实现。
【讨论】:
【参考方案4】:您可以改用GUI design pattern。或者构建一个有限的实现。
创建一个具有 DrawXArrayList 方法的 GUI 表单界面(其中 X 是一个有意义的名称。它有一个 ArrayList 类型的参数
创建一个名为 GUIView 的新类。它至少有两个方法:UpdateXArrayList和RegisterForm
当您初始化您的应用程序时,让 GUI 表单向实现 GUIView 的类注册自身。使实现 GUIView 的类对表单可见。
当您的 GUI 表单中的任何内容更新时,arraylist 将调用 UpdateXArrayList 作为它所做的最后一件事。然后,实现 GUIView 的类中的 UpdateXArrayList 方法将依次调用 DrawXArrayList 并传递更新的数组列表。实现 GUIFormInterface 的表单类中的 DrawXArrayList 将执行需要更新显示 ArrayList 的控件的步骤。
虽然与观察者和侦听器设置相比,这似乎需要很多步骤。您可以更好地控制各种用户操作如何影响 UI,然后是观察者 - 侦听器模式。此外,您在代码中记录了用户操作与 UI 更新之间的交互。
【讨论】:
【参考方案5】:为什么不使用绑定?
http://wiki.eclipse.org/index.php/JFace_Data_Binding
将您的 GUI 小部件绑定到您的列表。更改将在两个对象之间透明地传播。请务必使用适当的 observable 包装您的模型,例如 WritableList(如果直接使用 ArrayList)。
【讨论】:
【参考方案6】:如果您可以向应用程序添加新 jar,请查看 glazed Lists
【讨论】:
以上是关于我应该使用监听器还是观察器?的主要内容,如果未能解决你的问题,请参考以下文章
Delphi的基于接口(IInterface)的多播监听器模式(观察者模式 )
Electron Renderer 进程:我啥时候应该清理 IPC 监听器