Должен ли я использовать Listener или Observer?
У меня есть раскрывающийся список в моем графическом интерфейсе, который показывает содержимое ArrayList в другом классе.
Новые объекты могут быть добавлены в ArrayList в другом месте графического интерфейса, поэтому мне нужно знать, когда он обновляется, поэтому я могу обновить раскрывающееся меню. Из того, что я могу собрать, мои два варианта - расширить класс ArrayList, чтобы я мог добавить к нему свой собственный changeListener или сделать класс, который содержит рассматриваемый ArrayList, более заметным.
Что было бы более подходящим решением?
Ответы
Ответ 1
Два решения по существу являются реализациями одного и того же корневого шаблона проектирования (шаблон "Наблюдатель", как определено бандой четвертого.) В первом случае вы сами делаете ArrayList "наблюдаемым", в последнем вы являетесь делая объект домена, который использует список массивов "наблюдаемый".
Моя тенденция состояла бы в том, чтобы сделать последнее: сделать объект домена наблюдаемым. Это связано прежде всего с тем, что в конечном итоге у вас могут быть другие вещи, которые могут измениться в отношении объекта домена (для которого необходимо обновить графический интерфейс). Если он уже доступен, вы уже настроены.
Обратите внимание, что вам не нужно строго расширять java.util.Observable
- вы можете реализовать шаблон проектирования, не делая этого.
Ответ 2
Реализация Observable
в Java редко используется и не хорошо взаимодействует с Swing. Вместо этого используйте EventListener
.
В частности, есть ли причина не распространять 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); }
}
Ответ 3
Почему бы не использовать привязки?
http://wiki.eclipse.org/index.php/JFace_Data_Binding
Привяжите виджет GUI к своему списку. Изменения будут прототипировать между этими двумя объектами прозрачно. Обязательно оберните свою модель соответствующим наблюдаемым, например WritableList (если вы используете ArrayList напрямую).
Ответ 4
Всегда предпочитайте композицию над расширением (моя ссылка эффективна java и мой личный опыт). расширение ArrayList - просто обещание, что вы не будете нарушать какой-либо из инвариантов классов. Он также связывает вас с конкретной реализацией списка, которую вы расширяете.
Ответ 5
Вы можете переключиться на шаблон графического интерфейса пользователя. Или создайте ограниченную реализацию.
Создайте интерфейс формы GUI, который имеет метод DrawXArrayList (с X, являющимся некоторым значащим именем. Он имеет параметры типа ArrayList
Создайте новый класс GUIView. Он имеет как минимум два метода: UpdateXArrayList и RegisterForm
Когда вы инициализируете свое приложение, у вас есть регистр формы GUI с классом, реализующим GUIView. Сделайте класс, реализующий GUIView, видимым для формы.
Когда что-либо в вашей форме графического интерфейса обновляет, у arraylist есть вызов UpdateXArrayList как последнее, что он делает. Метод UpdateXArrayList в классе, реализующем GUIView, затем, в свою очередь, вызывает DrawXArrayList, передавая обновленный arraylist. DrawXArrayList в классе формы, реализующем GUIFormInterface, затем предпримет шаги, необходимые для обновления элемента управления, отображающего ArrayList.
Пока это похоже на множество шагов по сравнению с установкой наблюдателя и слушателя. У вас больше контроля над тем, как различные действия пользователя влияют на пользовательский интерфейс, а затем на шаблон наблюдателя-слушателя. Кроме того, вы зафиксировали в коде взаимодействие между действием пользователя и обновлениями пользовательского интерфейса.
Ответ 6
Если вы можете добавить новую банку в приложение, посмотрите застекленные списки