jface databinding:List,Set,Map对象的Observable代理封装

需求描述

对于一个已经存在的集合/映射对象(普通的List,Set,Map,非observable),我们希望把将它转换成一个observable对象,这个observable对象就像是原对象的代理一样,当对observable对象操作(增加删除元素)时,实际是对原对象的操作。
jface为List,Set,Map三种类型提供了对应的三种可写对象WritableList,WritableSet,WritableMap,研究了这三个类的代码,发现它们99%是满足这个需求,然并卵,因为构造函数上设计区别,造成这三个类的构造函数生成的observable对象与原对象是隔离的。
以WritableSet的构造函数为例,WritableSet的构造函数重新用外部传入的Collection的内容构造了一个新的HashSet对象,所以WritableSet中的Set对象与传入的原对象(Collection)没有半毛钱关系:

    public WritableSet(Realm realm, Collection c, Object elementType) {
        // 创建了一个新的Set对象传给父类的构造函数
        super(realm, new HashSet(c), elementType);
        this.elementType = elementType;
    }

只有WritableList类可以实现的上述的需求,而且貌似还是为了兼容之前版本的设计失误,而留的。
参见下面WritableList的构造函数的说明org.eclipse.core.databinding.observable.list.WritableList.WritableList(Realm realm, List toWrap, Object elementType)

    /** * Creates a writable list containing elements of the given type, wrapping * an existing client-supplied list. Note that for backwards compatibility * reasons, the contents of the created WritableList will change with the * contents of the given list. If this is not desired, * {@link #WritableList(Realm, Collection, Object)} should be used by * casting the second argument to {@link Collection}. * * @param realm * the observable's realm * @param toWrap * The java.util.List to wrap * @param elementType * can be null */
    public WritableList(Realm realm, List toWrap, Object elementType) {
        // 没有对toWrap做任何处理就传给了父类的构造函数,这才是我想要的
        super(realm, toWrap, elementType);
    }

所以这虽然是一个很普遍的需求,但jface并没有提供完整的支持,需要自己写代码支持。好在jface的基础框架比较扎实,所以如果搞清楚jface的类继承结构,自己写代码也不复杂,所以我为List,Set,Map三种类型的分别写了三个类用于实现Observable封装(WrappedObservableList,WrappedObservableSet,WrappedObservableMap),这三个类的代码都参考自对应的WritableList,WritableSet,WritableMap三个类,大部分代码都是直接抄来的。以下是三个类对应的实现代码

WrappedObservableList

WrappedObservableList类实现最简单,因为WritableList本身就因为历史原因支持这种代理封装,所以WrappedObservableList类只是在构造函数中加了参数检查
WrappedObservableList.java

package net.gdface.ui.binding;

import java.util.List;
import java.util.Objects;

import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.WritableList;

/** * 将指定的{@link List}对象(wrappedList)封装为 {@link ObservableList},
* 对observable对象的操作同步到原对象
* @author guyadong * * @param */
public class WrappedObservableList<E> extends WritableList<E> { public WrappedObservableList(List wrappedList, Object elementType) { this(Realm.getDefault(),wrappedList, elementType); } public WrappedObservableList(Realm realm, List wrappedList, Object elementType) { super(realm, Objects.requireNonNull(wrappedList,"the argument wrappedList must not be null"), elementType); } }

WrappedObservableSet

WrappedObservableSet类的大部分代码都抄自WritableSet
WrappedObservableSet.java

package net.gdface.ui.binding;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;

import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.set.ObservableSet;

/** * 将指定的{@link Set}对象(wrappedSet)封装为 {@link ObservableSet},
* 对observable对象的操作同步到原对象
* override方法实现代码抄自{@link org.eclipse.core.databinding.observable.set.WritableSet} * @author guyadong * * @param */
public class WrappedObservableSet<E> extends ObservableSet<E>{ /** * @param realm * @param wrappedSet 为null抛出异常 * @param elementType */ protected WrappedObservableSet(Realm realm, Set wrappedSet, Object elementType) { super(realm, Objects.requireNonNull(wrappedSet,"the argument wrappedSet must not be null"), elementType); } public WrappedObservableSet(Set wrappedSet, Object elementType) { this(Realm.getDefault(),wrappedSet, elementType); } public WrappedObservableSet(Set wrappedSet) { this(Realm.getDefault(),wrappedSet, null); } @Override public boolean add(E o) { getterCalled(); boolean added = wrappedSet.add(o); if (added) { Set removals = Collections.emptySet(); fireSetChange(Diffs.createSetDiff(Collections.singleton(o), removals)); } return added; } @Override public boolean addAll(Collection c) { getterCalled(); Set additions = new HashSet(); Iterator it = c.iterator(); while (it.hasNext()) { E element = it.next(); if (wrappedSet.add(element)) { additions.add(element); } } if (additions.size() > 0) { Set removals = Collections.emptySet(); fireSetChange(Diffs.createSetDiff(additions, removals)); return true; } return false; } @SuppressWarnings("unchecked") @Override public boolean remove(Object o) { getterCalled(); boolean removed = wrappedSet.remove(o); if (removed) { Set additions = Collections.emptySet(); fireSetChange(Diffs.createSetDiff(additions, Collections.singleton((E) o))); } return removed; } @SuppressWarnings("unchecked") @Override public boolean removeAll(Collection c) { getterCalled(); Set removes = new HashSet(); Iterator it = c.iterator(); while (it.hasNext()) { Object element = it.next(); if (wrappedSet.remove(element)) { removes.add((E) element); } } if (removes.size() > 0) { Set additions = Collections.emptySet(); fireSetChange(Diffs.createSetDiff(additions, removes)); return true; } return false; } @Override public boolean retainAll(Collection c) { getterCalled(); Set removes = new HashSet(); Iterator it = wrappedSet.iterator(); while (it.hasNext()) { E element = it.next(); if (!c.contains(element)) { it.remove(); removes.add(element); } } if (removes.size() > 0) { Set additions = Collections.emptySet(); fireSetChange(Diffs.createSetDiff(additions, removes)); return true; } return false; } @Override public void clear() { getterCalled(); Set removes = new HashSet(wrappedSet); Set additions = Collections.emptySet(); wrappedSet.clear(); fireSetChange(Diffs.createSetDiff(additions, removes)); } }

WrappedObservableMap

WrappedObservableMap的大部分代码也都是抄自WritableMap
WrappedObservableMap.java

package net.gdface.ui.binding;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.map.MapDiff;
import org.eclipse.core.databinding.observable.map.ObservableMap;
import org.eclipse.core.internal.databinding.observable.Util;

/** * 将指定的{@link Map}对象(wrappedMap)封装为 {@link ObservableMap},
* 对observable对象的操作同步到原对象
* override方法实现代码抄自 {@link org.eclipse.core.databinding.observable.map.WritableMap} * @author guyadong * * @param * @param */
public class WrappedObservableMap<K, V> extends ObservableMap<K, V> { private final Object keyType; private final Object valueType; public WrappedObservableMap(Map wrappedMap) { this(Realm.getDefault(),wrappedMap, null, null); } public WrappedObservableMap(Map wrappedMap, Object keyType, Object valueType) { this(Realm.getDefault(),wrappedMap, keyType, valueType); } /** * @param realm * @param wrappedMap 为null抛出异常 * @param keyType * @param valueType */ public WrappedObservableMap(Realm realm, Map wrappedMap, Object keyType, Object valueType) { super(realm, Objects.requireNonNull(wrappedMap,"the argument wrappedMap must not be null")); this.keyType=keyType; this.valueType=valueType; } @Override public Object getKeyType() { return keyType; } @Override public Object getValueType() { return valueType; } @Override public V put(K key, V value) { checkRealm(); boolean containedKeyBefore = wrappedMap.containsKey(key); V result = wrappedMap.put(key, value); boolean containedKeyAfter = wrappedMap.containsKey(key); if (containedKeyBefore != containedKeyAfter || !Util.equals(result, value)) { MapDiff diff; if (containedKeyBefore) { if (containedKeyAfter) { diff = Diffs.createMapDiffSingleChange(key, result, value); } else { diff = Diffs.createMapDiffSingleRemove(key, result); } } else { diff = Diffs.createMapDiffSingleAdd(key, value); } fireMapChange(diff); } return result; } @SuppressWarnings("unchecked") @Override public V remove(Object key) { checkRealm(); if (wrappedMap.containsKey(key)) { V result = wrappedMap.remove(key); fireMapChange(Diffs.createMapDiffSingleRemove((K) key, result)); return result; } return null; } @Override public void clear() { checkRealm(); if (!isEmpty()) { Map copy = new HashMap<>(wrappedMap); wrappedMap.clear(); fireMapChange(Diffs.createMapDiffRemoveAll(copy)); } } @Override public void putAll(Map map) { checkRealm(); Set addedKeys = new HashSet<>(map.size()); Map changes = new HashMap<>(map.size()); for (Map.Entry entry : map.entrySet()) { boolean add = !wrappedMap.containsKey(entry.getKey()); V previousValue = wrappedMap.put(entry.getKey(), entry.getValue()); if (add) { addedKeys.add(entry.getKey()); } else { changes.put(entry.getKey(), previousValue); } } if (!addedKeys.isEmpty() || !changes.isEmpty()) { Set removedKeys = Collections.emptySet(); fireMapChange(Diffs.createMapDiff(addedKeys, removedKeys, changes.keySet(), changes, wrappedMap)); } } }

注意

上面代码中使用了java8才有方法,所以要在java8下编译

你可能感兴趣的:(java,databinding)