Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use a Listener or Observer?

I have a dropdown box in my GUI which shows the contents of an ArrayList in another class. New objects can be added to the ArrayList elsewhere in the GUI, so I need to know when it is updated, so I can refresh the dropdown menu. From what I can gather, my two options are to extend the ArrayList class to allow me to add my own changeListener to it, or to make the class which contains the ArrayList in question extend observable.

Which would be a more appropriate solution?

like image 670
Simonw Avatar asked Apr 13 '09 17:04

Simonw


2 Answers

The two solutions are essentially implementations of the same root design pattern (the "Observer" pattern as defined by the Gang of Four.) In the former case, you are making the ArrayList itself "observable", in the latter you are making the domain object which uses the array list "observable."

My tendency would be to do the latter: make the domain object observable. This is primarily because you may eventually have other things that could change about the domain object (for which the GUI should be updated.) If it is already observable, you're already set.

Note that you don't strictly have to extend java.util.Observable - you can implement the design pattern without doing that.

like image 119
Jared Avatar answered Oct 06 '22 05:10

Jared


The Observable implementation in Java is rarely used, and doesn't inter-operate well with Swing. Use an EventListener instead.

In particular, is there a reason not to extend AbstractListModel or even use DefaultListModel directly when managing the contents of the list "elsewhere in the GUI"? Then your combo box could use a ComboBoxModel that delegates to the same ListModel instance, adding its own implementation to track the selection state.

I have in mind something like this (but I haven't test it):

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); }

}
like image 29
erickson Avatar answered Oct 06 '22 05:10

erickson