jface databinding:部分实现POJO对象的监测

在前一篇博文《jface databinding/PojoBindable实现对POJO对象的支持
》中,已经知道直接对POJO对象进行修改,是不能被绑定的UI组件知道的,在上一篇文章中虽然说到PojoBindable这个项目可以解决这个问题,但这个项目并不成熟,所以我没有采用这个方案,而且如果要改造所有的POJO类支持PropertyChangeSupport又实在太麻烦了。
仔细想想我的需求,退而求其次,不一定要直接修改POJO对象,就能实现数据同步可以不?
冷静回头再看相关的资料并做了一些试验,发现原来IObservableValue对象本身就有setValue方法用于修改被监控的对象的值,而且会通知到观察对象。

        DataBindingContext bindingContext = new DataBindingContext();
        // Text对象的text属性的IObservableValue 对象
        IObservableValue observeTextMyNametextObserveWidget = WidgetProperties.text(SWT.Modify).observe(myNametext);
        // Person对象name属性的IObservableValue 对象(Person是个实现了属性get/set方法的POJO类)
        namePersonObserveValue = PojoProperties.value("name").observe(person);
        // 数据绑定
        bindingContext.bindValue(observeTextMyNametextObserveWidget, namePersonObserveValue, null, null);
        // 调用IObservableValue.setValue方法修改数据对象的值,Text的内容会同步更新
        namePersonObserveValue.setValue("word");
        // 直接调用Person.setName方法来修改数据对象,Text不同步更新。
        person.setName("word")

这不就行了?将POJO对象封装起来提供IObservableValue,所有的Set方法IObservableValue.setValue方法来实现,后续修改POJO对象改为调用这个封装对象的Set方法,不就可以实现POJO对象的数据的监控了吗?
关键是在我这个项目里这样做的成本并不高,只是后续要改变一下对POJO对象的访问方式而已。于是根据这个思路,我写了一个稍通用化的POJO封装类来实现这个想法儿:
分两个类

ObservablePojoType 对POJO类进行可监控封装,为类的每个属性创建对应的IBeanValueProperty
ObservablePojoObject 对POJO对象进行可监控封装,为对象的每个属性创建对应的IObservableValue, 提供 setValue,getValue方法实现对POJO对象进行访问
ObservablePojoType.java

package testwb;

import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.databinding.beans.IBeanValueProperty;
import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import net.gdface.utils.Assert;
import net.gdface.utils.BeanPropertyUtils;

/** * 对POJO类进行可监控封装,为POJO类的每个属性创建对应的{@link IBeanValueProperty} * @see {@link PojoProperties#value(String)} * @see {@link IBeanValueProperty#observe(Object)} * @author guyadong * * @param  封装的POJO类 */
public class ObservablePojoType<T> {
    private final Class pojoType;
    private Map ivalueProperties=new HashMap();
    private final Map propertyDescriptors;
    public ObservablePojoType(Class pojoType) {
        if(null==pojoType)
            throw new NullPointerException();
        this.pojoType=pojoType;
        // 返回所有可读写的属性
        propertyDescriptors=BeanPropertyUtils.getProperties(pojoType, 3);
    }
    public ObservablePojoType(T pojo) {
        this((Class) pojo.getClass());
    }
    /** * 返回POJO类的所有属性名 * @return */
    public Set getPropertyNames() {
        return propertyDescriptors.keySet();
    }
    /** * 返回source对象的指定属性(propertyName)的{@link IObservableValue}对象 * @param source 监控目标对象 * @param propertyName 属性名 * @return */
    public IObservableValue observe(T source,String propertyName) {
        if(null==source)
            throw new NullPointerException();
        if(null==propertyName||propertyName.empty())
            throw new IllegalArgumentException();
        if(!propertyDescriptors.containsKey(propertyName))
            throw new IllegalArgumentException(String.format("invalid propertyName:%s",propertyName));
        if(!ivalueProperties.containsKey(propertyName)){
            ivalueProperties.put(propertyName, PojoProperties.value(propertyName));
        }
        return ivalueProperties.get(propertyName).observe(source);
    }

    /** * 返回指定对象的监控对象{@link ObservablePojoObject} * @param source * @return */
    public ObservablePojoObject observe(T source){
        return new ObservablePojoObject(source,this);
    }

    public PropertyDescriptor[] getPropertyDescriptors() {
        return propertyDescriptors.values().toArray(new PropertyDescriptor[0]);
    }
}

ObservablePojoObject.java

package testwb;

import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.internal.databinding.beans.BeanPropertyHelper;

/** * 对POJO对象进行可监控封装,为对象的每个属性创建对应的{@link IObservableValue}
* {@link #setValue(String, Object)}和 {@link #getValue(String)}实现对POJO对象进行访问
* 当调用 {@link #setValue(String, Object)}改变对象的属性值时,会自动通知监控对象
* * 这里将普通的Java bean(有get/set方法但没有通过PropertyChangeSupport实现属性监控)定义为POJO对象 * @author guyadong * * @param 封装的POJO类 */
public class ObservablePojoObject<T> { private final T pojo; private final ObservablePojoType pojoType; /** * 每个属性对应的{@link IObservableValue} */ private final Map observableValues=new HashMap(); public ObservablePojoObject(T pojo,ObservablePojoType pojoType) { if(null==pojo) throw new NullPointerException(); this.pojo = pojo; this.pojoType = null==pojoType?new ObservablePojoType((Class) pojo.getClass()):pojoType; } public ObservablePojoObject(T pojo) { this(pojo,null); } /** * 返回指定属性对应的{@link IObservableValue}对象 * @param propertyName * @return */ public IObservableValue getObservableProperty(String propertyName){ if(!pojoType.getPropertyNames().contains(propertyName)) throw new IllegalArgumentException(String.format("invalid propertyName:%s",propertyName)); if(!observableValues.containsKey(propertyName)){ observableValues.put(propertyName, pojoType.observe(pojo, propertyName)); } return observableValues.get(propertyName); } /** * 设置指定属性的值 * @param propertyName * @param value */ public void setValue(String propertyName,Object value){ getObservableProperty(propertyName).setValue(value); } /** * 获取指定属性的值 * @param propertyName * @return */ public Object getValue(String propertyName){ return getObservableProperty(propertyName).getValue(); } public T getPojo() { return pojo; } /** * 用from对象更新当前监控对象的所有属性 * @param from * @return * @see #setValue(String, Object) * @see {@link BeanPropertyHelper#readProperty(Object, PropertyDescriptor)} */ public ObservablePojoObject updateFrom(T from){ if(null==from) throw new NullPointerException(); for(PropertyDescriptor propertyDescriptor:pojoType.getPropertyDescriptors()){ setValue(propertyDescriptor.getName(), BeanPropertyHelper.readProperty(from, propertyDescriptor)); } return this; } }

测试代码:
TestPojoBinding4.java

package testwb;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Text;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.swt.widgets.Display;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class TestPojoBinding4 extends Dialog {

    /** * 数据对象定义 * @author guyadong * */
    public class Person {
        private String name;
        public Person(String name) {
            super();
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
            System.out.printf("updated %s\n",this.name);
        }
    }
    private DataBindingContext m_bindingContext;
    /** * 成员变量:数据对象 */
    protected Person personBak=new Person("hello!");
    protected Person person=new Person("hello!");
    private Text myNametext;
    /** * 将person封装成可监控的ObservablePojoObject对象 */
    private final ObservablePojoObject observablePersion=new ObservablePojoObject(person);;

    /** * Create the dialog. * @param parentShell */
    public TestPojoBinding4(Shell parentShell) {
        super(parentShell);
    }

    /** * Create contents of the dialog. * @param parent */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        container.setLayout(null);
        Button btnNewButton = new Button(container, SWT.NONE);
        btnNewButton.addSelectionListener(new SelectionAdapter() {
            @SuppressWarnings("unchecked")
            @Override
            public void widgetSelected(SelectionEvent e) {
                // 调用 ObservablePojoObject.setValue方法修改 person的name属性
                observablePersion.setValue("name", "word");
            }
        });
        btnNewButton.setBounds(38, 154, 80, 27);
        btnNewButton.setText("测试");

        myNametext = new Text(container, SWT.BORDER);
        myNametext.setBounds(38, 27, 80, 23);

        Button btnNewButton_1 = new Button(container, SWT.NONE);
        btnNewButton_1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                // 修改 person的name属性
                observablePersion.updateFrom(personBak);
            }
        });
        btnNewButton_1.setBounds(132, 154, 80, 27);
        btnNewButton_1.setText("恢复");

        return container;
    }

    /** * Create contents of the button bar. * @param parent */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
        m_bindingContext = initDataBindings();
    }

    /** * Return the initial size of the dialog. */
    @Override
    protected Point getInitialSize() {
        return new Point(362, 298);
    }
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestPojoBinding4 setting = new TestPojoBinding4(null);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    protected DataBindingContext initDataBindings() {
        DataBindingContext bindingContext = new DataBindingContext();
        IObservableValue observeTextMyNametextObserveWidget = WidgetProperties.text(SWT.Modify).observe(myNametext);
        // 数据绑定
        bindingContext.bindValue(observeTextMyNametextObserveWidget, observablePersion.getObservableProperty("name"), null, null);
        return bindingContext;
    }
}

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