5

いくつかの API 呼び出しIObservableList<E>から、Eclipse Databinding フレームワークから を取得しています。IObservableList<E>要素 type で定義されたいくつかの述語に従って、このものから別のものを派生させたいと思いEます。派生リストは、元のリストの変更に従って動的に更新する必要があります。

どうすればそれを最もよく実装できますか?サブクラス化を検討しましDecoratingObservableListたが、使い方がわかりませんでした。

もちろん、IObservableListインターフェイス全体を自分で実装することもできましたが、使用できるユーティリティ クラスが他にないのではないかと考えていました。

4

3 に答える 3

3

これは読み取り専用の実装です。

いくつかの注意事項:

  • これは、編集時にイベントを発生させるベース DecoratingObservableList に依存します。
  • イテレータの作成時間後に装飾されたリストが変更された場合、イテレータはライブになりません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();
    }
}
于 2012-04-13T20:30:14.303 に答える
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();}
}
于 2012-04-12T11:51:19.690 に答える
1

フィルター可能で監視可能なリストを持つGlazedListsのソース コードを確認することをお勧めします。

于 2012-04-12T14:14:24.733 に答える