初始化JavaBean

时间:2014-10-16 05:29:37

标签: java javabeans initializer

我发现自己制作了许多用于GUI构建的类(因此它们必须符合JavaBean模式)。这为初始化创建了一些问题。我经常有一些时间密集的方法,必须在设置状态后执行。

一种方法是记录必须执行方法init()并希望人们阅读并尊重它,但这是笨拙的并且意味着GUIBuilder不能按预期使用,而是额外的代码必须添加。

我已经检查了Bloch" Effective Java"这些论坛,当然我问谷歌博士,但我还没有想出任何东西。公平地说,它有点像一套多余的搜索词。

以下简短示例(显然是无关紧要的)演示了我目前的做法。我有一个" isInitialised"每当调用setter时,都会变量并使实例无效。每当在计算变量(或任何其他复杂方法)上调用getter时,都会检查isInitialised变量,并在需要时调用init()方法。

public class BeanTest {

    private int someValue;          // Just some number
    private float anotherValue;     // Just another number
    private double calculatedValue; // Calculated by some expensive process

    private boolean isInitialised = false;  // Is calculatedValue valid?

    /**
     * Default constructor made available for JavaBean pattern
     */
    public BeanTest() {
        someValue = 0;
        anotherValue = 0;
    }

    //******* Getters and setters follow ************/
    public int getSomeValue() {
        return someValue;
    }

    public void setSomeValue(int someValue) {
        if (someValue == this.someValue) {
            return;
        }        
        isInitialised = false;      // Calculated value is now invalid
        this.someValue = someValue;
    }

    public float getAnotherValue() {
        return anotherValue;
    }

    public void setAnotherValue(float anotherValue) {
        if (anotherValue == this.anotherValue) {
            return;
        }
        isInitialised = false;      // Calculated value is now invalid
        this.anotherValue = anotherValue;
    }

    /**
     * This is where the time expensive stuff is done.
     */
    public void init() {
        if (isInitialised) {
            return;
        }

        /* In reality this is some very costly process that I don't want to run often,
         * probably run in another thread */
        calculatedValue = someValue * anotherValue;

        isInitialised = true;
    }

    /**
     * Only valid if initialised
     */
    public double getCalculatedValue() {

        init();

        return calculatedValue;
    }

    /**
     * Code for testing
     */
    public static void main(String[] args) {
        BeanTest myBean = new BeanTest();
        myBean.setSomeValue(3);
        myBean.setAnotherValue(2);
        System.out.println("Calculated value: " + myBean.getCalculatedValue());
    }
}

这种方法有很多问题。例如,它没有很好地扩展(其中一些确实是为了扩展)。另外,我在这里只展示了一个带有三个变量的简单案例;真正的课程还有很多。事情变得一团糟。

任何人都可以提出一种不同的方法或模式,可以帮助我保持代码更优雅和可读性,并且仍然允许在GUI构建器中按预期工作吗?

P.S。 这是可变的。


EDITED

我认为通过琐事,我隐藏了一点。

诀窍是我只想运行init()一次,并且只在设置完所有内容时才运行。如果我正在使用构建器模式,这将很容易,因为我将它放在build()方法中,但这是在GUI元素中,因此是在JavaBean模式中。

我上面的代码是"模式的简单版本"我在用。这个模式确实有效,但是我注意到有许多弱点,尤其是可扩展性(是一个单词吗?)以及随着变量数量的增加。这个简单的例子看起来不错,但真正的代码开始变得可怕。

我想这可能只是JavaBean模式的一个弱点,但我想在我在我的包中制作了另外十几个狡猾的类之前我会问。

2 个答案:

答案 0 :(得分:1)

天真的方法:为什么不简单地在setter中调用init()呢?

更加花哨:使用PropertyChangeSupport对象。样品用法:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class TestBean implements PropertyChangeListener{
    private int someValue;
    private PropertyChangeSupport changeSupport;

    public TestBean() {
        changeSupport = new PropertyChangeSupport(this);
        changeSupport.addPropertyChangeListener(this);
    }

    private void init() {
        //do something time consuming, maybe even on a different thread, using Futures?
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        init();
    }

    public int getSomeValue() {
        return someValue;
    }

    public void setSomeValue(int someValue) {
        int oldValue = this.someValue;
        this.someValue = someValue;
        changeSupport.firePropertyChange("someValue", oldValue, someValue);
    }
}

答案 1 :(得分:0)

我认为我必须接受我想要实现的目标。以下是Bloch" Effective Java":

的引用
  

不幸的是,JavaBeans模式有其严重的缺点   拥有。因为构造是跨多个调用分开的,所以是一个JavaBean   可能在其构造的中途处于不一致的状态。该   class没有选择仅通过强制执行一致性   检查构造函数参数的有效性。

虽然它并没有完全回答我的问题,但我认为围绕isInitialized变量的任何答案都会遇到Bloch描述的问题。