从一些API调用中,我从Eclipse Databinding框架返回IObservableList<E>
。我希望根据元素类型IObservableList<E>
上定义的一些谓词从这个派生出另一个E
。应根据原始列表中的更改动态更新派生列表。
我怎样才能最好地实现它?我考虑过继承DecoratingObservableList
,但无法弄清楚如何使用它。
当然,我可以自己实现整个IObservableList
界面,但我想知道是否没有其他实用程序类可以使用。
答案 0 :(得分:3)
我认为延长DecoratingObservableList
是一个好的开始。我还建议专注于预期的用途,而不是立即实现整个API。例如,您是否需要通过set
进行随机访问?如果没有,那就不要打扰它了。这包含可变ObservableList
的只读视图,将已修饰列表的更改事件映射到已过滤列表上的相应更改事件:
public class FilteredObservableList<E> extends DecoratingObservableList
{
private final IObservableList decorated;
private final Predicate pred;
private final List<E> filtered = new ArrayList();
public FilteredObservableList(
IObservableList decorated, Predicate pred, boolean disposeDecoratedOnDispose)
{
super(decorated, disposeDecoratedOnDispose);
this.decorated = decorated;
this.pred = pred;
for (Object o : decorated) filtered.add(pred.eval(o)? (E) o : null);
}
@Override protected void handleListChange(ListChangeEvent event) {
final List<ListDiffEntry> diffs = new ArrayList();
final List<Integer> mapping = new ArrayList();
int i = 0;
for (E e : filtered) mapping.add(e != null? i++ : i);
event.diff.accept(new ListDiffVisitor() {
@Override public void handleAdd(int index, Object element) {
final boolean passes = pred.eval(element);
filtered.add(index, passes? (E) element : null);
final Integer outInd = mapping.get(index);
mapping.add(index, outInd);
if (passes) {
diffs.add(new FilteredDiffEntry(outInd, true, element));
for (int i = index + 1; i < mapping.size(); i++)
mapping.set(i, mapping.get(i) + 1);
}
}
@Override public void handleRemove(int index, Object element) {
final boolean passes = filtered.get(index) != null;
filtered.remove(index);
final int outInd = mapping.get(index);
mapping.remove(index);
if (passes) {
diffs.add(new FilteredDiffEntry(outInd, false, element));
for (int i = index; i < mapping.size(); i++)
mapping.set(i, mapping.get(i)-1);
}
}
});
if (!diffs.isEmpty()) {
final ListDiffEntry[] difAry = diffs.toArray(new ListDiffEntry[diffs.size()]);
fireListChange(new ListDiff() {
@Override public ListDiffEntry[] getDifferences() { return difAry; }
});
}
}
public ListIterator<E> listIterator() {
getterCalled();
final Iterator<E> it = decorated.iterator();
return new ListIterator<E>() {
E next;
boolean nextReady;
public boolean hasNext() {
getterCalled();
if (nextReady) return true;
while (it.hasNext()) {
next = it.next();
if (next != null) { nextReady = true; break; }
}
return nextReady;
}
public E next() {
getterCalled();
if (hasNext()) { nextReady = false; return next; }
else throw new NoSuchElementException();
}
public void add(Object o) { throw new UnsupportedOperationException(); }
public boolean hasPrevious() { throw new UnsupportedOperationException(); }
public int nextIndex() { throw new UnsupportedOperationException(); }
public E previous() { throw new UnsupportedOperationException(); }
public int previousIndex() { throw new UnsupportedOperationException(); }
public void remove() { throw new UnsupportedOperationException(); }
public void set(Object o) { throw new UnsupportedOperationException(); }
};
}
public interface Predicate { boolean eval(Object o); }
private static final class FilteredDiffEntry extends ListDiffEntry {
private final int pos;
private final boolean isAdd;
private final Object el;
FilteredDiffEntry(int pos, boolean isAdd, Object el) {
this.pos = pos; this.isAdd = isAdd; this.el = el;
}
@Override public int getPosition() { return pos; }
@Override public boolean isAddition() { return isAdd; }
@Override public Object getElement() { return el; }
}
@Override public Object move(int _, int __) { throw new UnsupportedOperationException(); }
@Override public Object remove(int _) { throw new UnsupportedOperationException(); }
@Override public Object set(int _, Object __) { throw new UnsupportedOperationException(); }
@Override public void add(int _, Object __) { throw new UnsupportedOperationException(); }
@Override public boolean add(Object _) { throw new UnsupportedOperationException(); }
@Override public boolean addAll(Collection _) { throw new UnsupportedOperationException(); }
@Override public boolean addAll(int _, Collection __) {
throw new UnsupportedOperationException();
}
@Override public void clear() { throw new UnsupportedOperationException(); }
@Override public boolean remove(Object _) { throw new UnsupportedOperationException(); }
@Override public boolean removeAll(Collection _) { throw new UnsupportedOperationException();}
@Override public boolean retainAll(Collection _) { throw new UnsupportedOperationException();}
}
答案 1 :(得分:3)
这是一个只读实现。
有几点需要注意:
CopyOnWriteArrayList
那样工作。可以说它应该抛出ConcurrentModificationExceptions
。如果它必须是可写的,你可以定义你想要如何进行索引映射,也可以指定你是否允许列表中的非唯一项?
package filteredobservablelist;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.core.databinding.observable.list.DecoratingObservableList;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
import org.eclipse.core.databinding.observable.list.ListDiff;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
public class FilteredObservableList extends DecoratingObservableList {
private static final class FilteredListDiff extends ListDiff {
private final List<ListDiffEntry> filteredDiffs;
private FilteredListDiff(List<ListDiffEntry> filteredDiffs) {
this.filteredDiffs = filteredDiffs;
}
@Override
public ListDiffEntry[] getDifferences() {
return filteredDiffs.toArray(new ListDiffEntry[filteredDiffs.size()]);
}
}
public interface Predicate {
boolean evaluate(Object element);
}
private final Predicate predicate;
private List<Object> filteredList;
public FilteredObservableList(IObservableList decorated, boolean disposeDecoratedOnDispose, Predicate predicate) {
super(decorated, disposeDecoratedOnDispose);
this.predicate = predicate;
rebuildCache();
}
@Override
protected void handleListChange(final ListChangeEvent event) {
final List<ListDiffEntry> filteredDiffs = new ArrayList<ListDiffEntry>(event.diff.getDifferences().length);
for (ListDiffEntry element : event.diff.getDifferences()) {
if (predicate.evaluate(element.getElement())) {
filteredDiffs.add(element);
}
}
rebuildCache();
if (!filteredDiffs.isEmpty()) {
fireListChange(new FilteredListDiff(filteredDiffs));
}
}
private void rebuildCache() {
filteredList = new ArrayList<Object>();
for (Object element : getDecorated()) {
if (predicate.evaluate(element)) {
filteredList.add(element);
}
}
}
@Override
public boolean contains(Object o) {
return filteredList.contains(o);
}
@Override
public boolean containsAll(Collection c) {
return filteredList.containsAll(c);
}
@Override
public Object get(int index) {
getterCalled();
return filteredList.get(index);
}
@Override
public int indexOf(Object o) {
getterCalled();
return filteredList.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
getterCalled();
return filteredList.lastIndexOf(o);
}
@Override
public List subList(int fromIndex, int toIndex) {
getterCalled();
return this.filteredList.subList(fromIndex, toIndex);
}
@Override
public IObservableList getDecorated() {
return (IObservableList) super.getDecorated();
}
@Override
public Iterator iterator() {
return listIterator();
}
@Override
public ListIterator listIterator() {
return this.listIterator(0);
}
@Override
public ListIterator listIterator(int index) {
getterCalled();
final ListIterator iterator = filteredList.listIterator(index);
return new ListIterator() {
@Override
public boolean hasNext() {
getterCalled();
return iterator.hasNext();
}
@Override
public boolean hasPrevious() {
getterCalled();
return iterator.hasPrevious();
}
@Override
public Object next() {
getterCalled();
return iterator.next();
}
@Override
public int nextIndex() {
getterCalled();
return iterator.nextIndex();
}
@Override
public Object previous() {
getterCalled();
return iterator.previous();
}
@Override
public int previousIndex() {
getterCalled();
return iterator.previousIndex();
}
@Override
public void add(Object o) {
throw new UnsupportedOperationException();
}
@Override
public void set(Object o) {
throw new UnsupportedOperationException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public Object move(int oldIndex, int newIndex) {
throw new UnsupportedOperationException();
}
@Override
public Object remove(int index) {
throw new UnsupportedOperationException();
}
@Override
public Object set(int index, Object element) {
throw new UnsupportedOperationException();
}
@Override
public void add(int index, Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(int index, Collection c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection c) {
throw new UnsupportedOperationException();
}
}
答案 2 :(得分:1)
您可能希望查看具有可过滤,可观察列表的GlazedLists的源代码。