【问题标题】:Java: Why do we us property change listeners instead of direct pointing to single value?Java:为什么我们使用属性更改侦听器而不是直接指向单个值?
【发布时间】:2016-05-09 18:37:29
【问题描述】:

监听器的想法是,对象的某些字段(或属性)发生变化,所有“注册”的监听器都会被“通知”并将新值复制到它们的字段中。 然而,这难道不是一种不必要的复杂和冗余的设计吗? 这是一个简单的建议,可以根据需要通过直接值指向和收件箱来解决问题。 例如,如果是字符串字段:

public class StringBox {

protected String value;

public String getValue() {
    return value;
}

public void setValueAtomic(String value) {
    this.value = value;
}

public StringBox(String value) {
    this.value = value;
}

public StringBox() {

}

@Override
public String toString() {
    return "StringBox{" + "value=" + value + '}';
}

}
public class StringListenerReplacer {

    protected StringBox field;


public StringListenerReplacer(StringBox field) {
    this.field = field;
}

public void setField(String field){
    this.field.setValueAtomic(field);
}

public String getField(){
    return this.field.getValue();
}
}

public class DemoMain {

public static void main(String[] args) {

    StringBox field = new StringBox("DemoMain");

    StringListenerReplacer s0 = new StringListenerReplacer(field);
    StringListenerReplacer s1 = new StringListenerReplacer(field);
    StringListenerReplacer s2 = new StringListenerReplacer(field);
    StringListenerReplacer s3 = new StringListenerReplacer(field);
    StringListenerReplacer s4 = new StringListenerReplacer(field);
    StringListenerReplacer s5 = new StringListenerReplacer(field);

    System.out.println("Now, it is quasi a listener set to the string field value, so if one object change it, it changes for all");

    System.out.println("s0.getField() = " + s0.getField());

    System.out.println("Now, for example s4 changes field");

    s4.setField("another value");

    System.out.println("s0.getField() = " + s0.getField());
    System.out.println("s1.getField() = " + s1.getField());
    System.out.println("s2.getField() = " + s2.getField());
    System.out.println("s3.getField() = " + s3.getField());
    System.out.println("s4.getField() = " + s4.getField());
    System.out.println("s5.getField() = " + s5.getField());

}

}

对于监听器设计,不谈论它会在语法上看起来很奇怪, 每个对象都会引用另一个 (6*5 = 30 个引用),6 个字符串字段的副本,并且每次更改 或字段,将调用在所有侦听器的循环中具有 5 次调用 的 firePropertyChange。 现在我明白了,为什么例如 Eclipse 或 Netbeans IDE 在弱笔记本电脑上非常慢,从 akku 工作。 所以问题是,为什么人们在编程中总体使用监听器?

【问题讨论】:

    标签: java eclipse netbeans listener


    【解决方案1】:

    侦听器的思想是,对象的某些字段(或属性)发生变化,所有“注册”的侦听器都将被“通知”并将新值复制到其字段中。

    我认为这个前提是错误的。我喜欢使用侦听器,通常是观察者模式,但从未以这种方式使用它们。

    您可能希望在单击按钮时执行操作。例如将一些文本打印到控制台。与其不断轮询按钮的变化,而是让每个侦听器都通过按钮调用侦听器,效率更高。

    即使您在单击按钮的帧期间引用了变量isClicked(即true),您也必须不断检查if(isClicked) {...},每个侦听器。

    【讨论】:

      【解决方案2】:

      我可以看到您的设计的一大缺点是必须访问 StringListenerReplacer 对象才能更改值并让它“侦听”更改。

      如果我有几十个不同的、几乎不相关的类或逻辑代码块可能会或可能不会影响相关对象,会发生什么?侦听器模式允许侦听器收到更改通知,无论程序处于什么状态或可以访问它。

      它对于多线程也更有用,其中我们可以跨线程同步侦听器以等待值更改甚至远程调用。这些线程可以处于完全不同的状态或执行代码块,并且侦听器将始终得到适当的通知。

      【讨论】:

        【解决方案3】:

        监听器设计的正式名称叫做observer。您是正确的,设置侦听器确实会增加代码和复杂性。因此,您不会将侦听器用于简单的 POJO。您主要将它用于事件和队列。

        视频游戏是使用可观察模式的一个很好的例子,但不胜枚举。我在一个到处都有事件的游戏中工作。其中一个事件是暂停事件。起初,我会手动通知所有需要了解暂停事件、每个敌人和弹丸以及音乐等的对象。我一直这样做是因为将可观察模式添加到游戏的这一部分的成本和复杂性。但是过了一段时间,随着列表的增长,手动通知所有对象变得太困难了。所以我硬着头皮实现了可观察模式。这对降低我的代码复杂性产生了总体影响。使用可观察模式,任何需要通知暂停事件的对象都会自行注册,以便在该事件发生时收到通知。

        事件和队列可能有点明显。让我给你举一个更普通的例子,也涉及同一个视频游戏。游戏是用 JavaFX 编码的,JavaFX 已经在它们的类中内置了可观察的模式。我注册了监听器,以便在屏幕上的对象发生变化时得到通知。例如,我记得屏幕上有一个对象 X,它的位置取决于另一个对象 Y 的位置。所以我设置了一个侦听器,以便当对象 Y 的坐标发生变化时,我会在屏幕上重新排列对象 X。这个例子展示了它是如何对类的属性有用的。

        【讨论】:

          猜你喜欢
          • 2011-12-23
          • 1970-01-01
          • 1970-01-01
          • 2014-11-10
          • 2018-06-10
          • 2020-01-24
          • 2012-03-17
          • 2015-08-21
          • 2010-11-07
          相关资源
          最近更新 更多