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

时间:2009-04-13 17:49:03

标签: java swing arraylist listener observer-pattern

我的GUI中有一个下拉框,显示另一个类中ArrayList的内容。 可以将新对象添加到GUI中其他位置的ArrayList,因此我需要知道它何时更新,因此我可以刷新下拉菜单。从我可以收集的内容来看,我的两个选项是扩展ArrayList类以允许我将自己的changeListener添加到它,或者使包含有问题的ArrayList的类扩展为可观察的。

哪种解决方案更合适?

6 个答案:

答案 0 :(得分:11)

这两个解决方案基本上是相同根设计模式的实现(四人帮定义的“观察者”模式。)在前一种情况下,你使ArrayList本身“可观察”,在后者你是使用数组列表的域对象“observable。”

我倾向于做后者:使域对象可观察。这主要是因为您最终可能会有其他可能更改域对象的事情(应该更新GUI。)如果已经可以观察到,那么您已经设置好了。

请注意,您不必严格延伸java.util.Observable - 您可以在不执行此操作的情况下实现设计模式。

答案 1 :(得分:9)

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 :(得分:2)

为什么不使用绑定?

http://wiki.eclipse.org/index.php/JFace_Data_Binding

将GUI小部件绑定到列表。变化将透明地传播两个对象。确保使用适当的observable包装模型,例如WritableList(如果直接使用ArrayList)。

答案 3 :(得分:1)

总是喜欢构图而不是扩展(我的参考是有效的java和我的个人经验)。扩展ArrayList只是一个承诺,你不会违反任何类不变量。它还会将您绑定到您正在扩展的特定列表实现。

答案 4 :(得分:0)

您可以切换为使用GUI design pattern。或者构建一个有限的实现。

创建一个GUI表单接口,该接口具有DrawXArrayList方法(X是一个有意义的名称。它的参数类型为ArrayList

创建一个名为GUIView的新类。它至少有两个方法:UpdateXArrayList和RegisterForm

初始化应用程序时,GUI表单会自动注册实现GUIView的类。使实现GUIView的类对表单可见。

当GUI表单中的任何内容更新时,arraylist会将它调用UpdateXArrayList作为它的最后一件事。实现GUIView的类中的UpdateXArrayList方法将依次调用DrawXArrayList传递更新的arraylist。实现GUIFormInterface的表单类中的DrawXArrayList将采取更新显示ArrayList的控件的步骤。

虽然与观察者和听众设置相比,这似乎有很多步骤。您可以更好地控制各种用户操作如何影响UI,然后是观察者 - 侦听器模式。此外,您还在代码中记录了用户操作与UI更新之间的交互。

答案 5 :(得分:0)

如果您可以向应用程序添加新jar,请查看glazed Lists