我应该使用监听器还是观察器?

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

【讨论】:

以上是关于我应该使用监听器还是观察器?的主要内容,如果未能解决你的问题,请参考以下文章

波哥带你探寻SpringBoot中优雅设计监听器的本质

Spring事件监听机制源码解析

Delphi的基于接口(IInterface)的多播监听器模式(观察者模式 )

Electron Renderer 进程:我啥时候应该清理 IPC 监听器

如何实现一个 Firebase 监听器来观察数据库的实时变化

发布订阅模式和观察者模式