Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
themeEclipse
languagejava
titleData Model
linenumberstrue
class DataModel {
	private List<MyDataItem> _data = new LinkedList<MyDataItem>();

	protected void fireEvent(final DataModelChangeEvent event) {
		// notifies the registered event listeners about the change - code omitted for better visibility.
	}

	public void addItem(final MyDataItem newItem) {
		_data.add(newItem);
		fireEvent(new DataModelChangeEvent(this, ITEM_ADDED, newItem));
	}

	public void removeItem(final MyDataItem itemToRemove) {
		_data.remove(itemToRemove);
		fireEvent(new DataModelChangeEvent(this, ITEM_REMOVED, itemToRemove));
	}

	public List<MyDataItem> getData() {
		return _data;
	}
	public void setData(final List<MyDataItem> list) {
		_data = list;
		fireEvent(new DataModelChangeEvent(this, MODEL_CHANGED, null));
	}
}

I'm sure now you have the point, but just allow me to emphasize it. In the model, whenever an item is added or removed, the notification is sent automatically. Then, for whatever reason (e.g. due to a misinterpreted performance enhancement), the List is exposed to the public. Yeah, the _data will refer to the very same List instance, regardless what happens in the code that calls the getData() method. But the content of the list is not safe any more. Whoever grabs a reference to the list (that's what the getData method provides), may make changes by adding or removing elements - and the model won't know anything about it. That's, ladies and gentlemen, is one of the best ways of inducing hardly discoverable, randomly occurring bugs into our application. In this particular case, the solution is simple - use the Collections class to create an immutable version of our list and provide that reference to the public. But if we have to allow the external code to change the content of the list, then instead of giving the reference, implement the Iterable interface, and return with a local implementation of the Iterator, which sends the proper notifications. But all these are possible only because we're talking about a collection. But the problem is more general than that - if part of the state of the object is another object (and a reference to that other object is held), then we shouldn't allow access to that other object, unless it is immutable. And how to do it in general? Sorry, no general solution exists. It's our responsibility to keep this rule.

...