BaseObservableList
Martin Sladecek
martin.sladecek at oracle.com
Wed Dec 14 02:43:20 PST 2011
Hello,
I'm working on http://javafx-jira.kenai.com/browse/RT-15029 and as part
of this effort, I'm doing a refactoring of ObservableListWrapper.
So I've created an abstract class BaseObservableList (extends
AbstractList) that could serve as a base class for all ObservableLists
implementations.
For a simple (modifiable) implementation, one would need to implement
following methods:
public int size() {
}
public E get(int index) {
}
protected void doAdd(int index, E element) {
}
protected E doRemove(int index) {
}
protected E doSet(int index, E element) {
}
So something like ObservableListWrapper would look like this:
private final List<E> backingList;
protected List<E> getBackingList() {
return backingList;
}
public ObservableListWrapper(List<E> backingList) {
this.backingList = backingList;
}
@Override
public int size() {
return backingList.size();
}
@Override
public E get(int index) {
return backingList.get(index);
}
@Override
protected void doAdd(int index, E element) {
backingList.add(index, element);
}
@Override
protected E doRemove(int index) {
return backingList.remove(index);
}
@Override
protected E doSet(int index, E element) {
return backingList.set(index, element);
}
The methods from List interface like add, set, remove, etc.. then
delegate calls to do* methods and report changes to ListChangeListeners,
so you don't need to worry about this.
Now when somebody would want to override something else or extend the
implementation, an IterableChangeBuilder, that's used in
BaseObservableList, needs to be used for this purpose.
So when creating something by delegating to the methods from the List,
you just need to wrap the block in
changeBuilder.beginComplexChange(); and changeBuilder.endComplexChange();
This builds up the change in the calls in between instead of calling the
observers multiple times.
E.g. setAll method works like this
public boolean setAll(Collection<? extends E> col) {
changeBuilder.beginComplexChange();
clear(); //does not call ListChangeListeners
addAll(col); //neither does this
changeBuilder.endComplexChange(); //this calls the ListChangeListeners using just one Change object
return true;
}
On the other hand, if you want to override something simple like
add/remove/set or use just doSet, doAdd and doRemove methods or you
directly manipulate with your data structure, you have to use a
different pattern and use methods from the IterableChangeBuilder (there
are methods like nextAdd, nextRemove, nextSet). And then end it with
commit() call.
So, e.g. you want to implement some fast clear() (the original clear in
AbstractList iterates over the elements and remove them one by one,
building up the resulting change on the way), you would do:
public void clear() {
//do the fast clear
changeBuilder.nextRemove(0, listOfRemovedItems);
changeBuilder.commit(); //Calls the ListChangeListeners, but only if not in ComplexChange block
}
Of course, these 2 patterns could be combined and you can do something
like this:
changeBuilder.beginComplexChange();
clear(); //no call to observers, as we are in ComplexChange block.
// do some stuff using doAdd or by directly changing my data structures
chnageBuilder.nextAdd(0, x); //I've added something so I need to report this
changeBuilder.endComplexChange(); //calls the ListChangeListeners
What do you think about this API?
Thanks,
-Martin
More information about the openjfx-dev
mailing list