Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >jface databinding:List,Set,Map对象的Observable代理封装

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

作者头像
10km
发布于 2018-01-03 03:38:24
发布于 2018-01-03 03:38:24
62200
代码可运行
举报
文章被收录于专栏:10km的专栏10km的专栏
运行总次数:0
代码可运行

需求描述

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public WritableSet(Realm realm, Collection<? extends E> c, Object elementType) {
        // 创建了一个新的Set对象传给父类的构造函数
        super(realm, new HashSet<E>(c), elementType);
        this.elementType = elementType;
    }

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 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 <code>null</code>
     */
    public WritableList(Realm realm, List<E> 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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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},<br>
 * 对observable对象的操作同步到原对象<br>
 * @author guyadong
 *
 * @param <E>
 */
public class WrappedObservableList<E> extends WritableList<E> {

    public WrappedObservableList(List<E> wrappedList, Object elementType) {
        this(Realm.getDefault(),wrappedList, elementType);
    }

    public WrappedObservableList(Realm realm, List<E> wrappedList, Object elementType) {
        super(realm, Objects.requireNonNull(wrappedList,"the argument wrappedList must not be null"), elementType);
    }   
}

WrappedObservableSet

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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},<br>
 * 对observable对象的操作同步到原对象<br>
 * override方法实现代码抄自{@link org.eclipse.core.databinding.observable.set.WritableSet}
 * @author guyadong
 *
 * @param <E>
 */
public class WrappedObservableSet<E> extends ObservableSet<E>{

    /**
     * @param realm
     * @param wrappedSet 为null抛出异常
     * @param elementType
     */
    protected WrappedObservableSet(Realm realm, Set<E> wrappedSet, Object elementType) {
        super(realm, Objects.requireNonNull(wrappedSet,"the argument wrappedSet must not be null"), elementType);       
    }

    public WrappedObservableSet(Set<E> wrappedSet, Object elementType) {
        this(Realm.getDefault(),wrappedSet, elementType);
    }
    public WrappedObservableSet(Set<E> wrappedSet) {
        this(Realm.getDefault(),wrappedSet, null);
    }
    @Override
    public boolean add(E o) {
        getterCalled();
        boolean added = wrappedSet.add(o);
        if (added) {
            Set<E> removals = Collections.emptySet();
            fireSetChange(Diffs.createSetDiff(Collections.singleton(o), removals));
        }
        return added;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        getterCalled();
        Set<E> additions = new HashSet<E>();
        Iterator<? extends E> it = c.iterator();
        while (it.hasNext()) {
            E element = it.next();
            if (wrappedSet.add(element)) {
                additions.add(element);
            }
        }
        if (additions.size() > 0) {
            Set<E> 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<E> additions = Collections.emptySet();
            fireSetChange(Diffs.createSetDiff(additions,
                    Collections.singleton((E) o)));
        }
        return removed;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean removeAll(Collection<?> c) {
        getterCalled();
        Set<E> removes = new HashSet<E>();
        Iterator<?> it = c.iterator();
        while (it.hasNext()) {
            Object element = it.next();
            if (wrappedSet.remove(element)) {
                removes.add((E) element);
            }
        }
        if (removes.size() > 0) {
            Set<E> additions = Collections.emptySet();
            fireSetChange(Diffs.createSetDiff(additions, removes));
            return true;
        }
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        getterCalled();
        Set<E> removes = new HashSet<E>();
        Iterator<E> it = wrappedSet.iterator();
        while (it.hasNext()) {
            E element = it.next();
            if (!c.contains(element)) {
                it.remove();
                removes.add(element);
            }
        }
        if (removes.size() > 0) {
            Set<E> additions = Collections.emptySet();
            fireSetChange(Diffs.createSetDiff(additions, removes));
            return true;
        }
        return false;
    }

    @Override
    public void clear() {
        getterCalled();
        Set<E> removes = new HashSet<E>(wrappedSet);
        Set<E> additions = Collections.emptySet();
        wrappedSet.clear();
        fireSetChange(Diffs.createSetDiff(additions, removes));
    }
}

WrappedObservableMap

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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},<br>
 * 对observable对象的操作同步到原对象<br>
 * override方法实现代码抄自 {@link org.eclipse.core.databinding.observable.map.WritableMap}
 * @author guyadong
 *
 * @param <K>
 * @param <V>
 */
public class WrappedObservableMap<K, V> extends ObservableMap<K, V> {

    private final Object keyType;
    private final Object valueType;

    public WrappedObservableMap(Map<K, V> wrappedMap) {
        this(Realm.getDefault(),wrappedMap, null, null);
    }

    public WrappedObservableMap(Map<K, V> 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<K, V> 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<K, V> 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<K, V> copy = new HashMap<>(wrappedMap);
            wrappedMap.clear();
            fireMapChange(Diffs.createMapDiffRemoveAll(copy));
        }
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map) {
        checkRealm();
        Set<K> addedKeys = new HashSet<>(map.size());
        Map<K, V> changes = new HashMap<>(map.size());
        for (Map.Entry<? extends K, ? extends V> 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<K> removedKeys = Collections.emptySet();
            fireMapChange(Diffs.createMapDiff(addedKeys, removedKeys,
                    changes.keySet(), changes, wrappedMap));
        }
    }

}

注意

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年01月05日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jface databinding:部分实现POJO对象的监测
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53839050
10km
2019/05/25
4670
jface databinding:延迟计算--ComputedValue和WritableList使用的例子
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53783629
10km
2019/05/25
4140
jface databinding: 创建readonly(只读)可观察对象(observable)
该文章介绍了在Java中如何使用unmodifiableXXX系列方法来创建只读变量,包括List、Map、Set和Observable等数据结构。具体代码示例包括创建List副本、创建Map副本和创建Set副本等。这些方法能帮助我们创建不可修改的副本,从而更好地保护数据不被修改。
10km
2018/01/03
8970
jface databinding: 创建readonly(只读)可观察对象(observable)
jface databinding/PojoBindable实现对POJO对象的支持
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53811946
10km
2019/05/25
5770
jface databinding:使用CheckboxTableViewer实现表中(Set)对象与CheckTable中选中条目数据绑定
该文介绍了如何使用JFace Data Binding Library实现Eclipse JFace Table Viewer的选中行高亮效果。
10km
2018/01/03
1.8K0
jface databinding:使用CheckboxTableViewer实现表中(Set)对象与CheckTable中选中条目数据绑定
jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定
需求说明 如下图,一个可多选的List组件,初始表有3个值,希望实现与一个java.util.List对象(保存选中的值)的双向数据绑定。当List组件中选中的内容变化时,java.util.List
10km
2018/01/03
9200
jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定
jface databinding:label provider 实现多列表格(Table)数据绑定的两个途径
显示需求 如下图,希望将一组拥有两个字段的表与两列的table绑定在一起,实现自动显示。 在jface viewer中label provider用于提供数据对象到视图对象(viewer)
10km
2018/01/03
1.8K0
jface databinding:label provider 实现多列表格(Table)数据绑定的两个途径
jface databinding(数据挷定)中的数据转换(IConverter)和数据验证(IValidator )
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53793478
10km
2019/05/25
9870
jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定
需求说明 如下是一个简单的测试对话框,我们希望当”起始日期”按钮为勾选时,数据对象dataBean的date属性为日期组件DateTime选择的值,否则为null. 先给出DateBean
10km
2018/01/03
9240
jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定
jface databinding:输入无效数值时强制恢复初始值-updateModelToTarget
本文讲述通过自定义Binding,实现floatValue文本框和float类型的绑定,并支持数据校验。通过示例代码,展示了如何在SWT Binding的简单应用场景。同时分析了ValueBinding的实现原理,以及其与Binding的区别。
10km
2018/01/03
1.2K0
jface databinding:输入无效数值时强制恢复初始值-updateModelToTarget
JDK 工具类之 Collections 3
/** * Returns a dynamically typesafe view of the specified sorted map. * Any attempt to insert a mapping whose key or value have the wrong * type will result in an immediate {@link ClassCastException}. * Similarly, any attempt to mo
一个会写诗的程序员
2022/05/13
3910
jface databinding:构建一个改进版的通用型数值验证器StringToNumberValidator
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53868597
10km
2019/05/25
4190
java之集合(Set、List、Map)
HashSet是Set接口的典型实现,大多数时候使用Set集合时都会使用这个实现类。我们大多数时候说的Set集合指的就是HashSet。
西西嘛呦
2020/08/26
5190
记一下Shiro重构之Redis Catch
程序员朱永胜
2023/08/17
1300
JDK 工具类之 Collections 2
/** * Returns a synchronized (thread-safe) map backed by the specified * map. In order to guarantee serial access, it is critical that * <strong>all</strong> access to the backing map is accomplished * through the returned map.<p>
一个会写诗的程序员
2022/05/13
3830
List,Map 三种遍历方式:(总结理解)
☀️相关笔记章节: 🌹java 1.8 stream使用总结(个人总结有一些经典文章的集合) 🌹遍历 ArrayList和遍历 Map的几种方式 🌹Java对象,Map,List,Set数组等相互转换大全(详细讲解,附代码,讲解案例) 🌹List,Map多层循环嵌套Demo及其理解 🌹List,Map 三种遍历方式:(总结理解) 🌹List<Map<String, Object>>,Map<String,List<Map<String, Object>>>多方式循环遍历
默 语
2024/11/20
5240
DataBinding最全使用说明
如果你要在Android实现MVVM架构, 那么DataBinding是你的不二选择. MVVM也是目前所有前端/iOS/Android领域主流发展方向
用户9253515
2021/12/28
2.3K0
Java学习笔记——集合
存储对象可以使用数组 (基本数据类型 & 引用数据类型) 和集合 (引用数据类型),用数组存储对象的弊端有:一旦创建,其长度不可变;数组中真正存储的对象个数不可知,除非自定义类。使用集合可以解决这些问题。
梦飞
2022/06/23
2740
Java学习笔记——集合
Java学习笔记——Set接口和Map接口
add(E e)                          确保此 collection 包含指定的元素(可选操作)。
用户7886150
2021/04/26
8630
jface databinding:更简单的ISideEffect实现多目标单边数据绑定塈其原理分析
10km
2018/01/03
1.1K0
jface databinding:更简单的ISideEffect实现多目标单边数据绑定塈其原理分析
推荐阅读
相关推荐
jface databinding:部分实现POJO对象的监测
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验