Java:为什么我们要更改侦听器而不是直接指向单个值?

Java:为什么我们要更改侦听器而不是直接指向单个值?,java,eclipse,netbeans,listener,Java,Eclipse,Netbeans,Listener,侦听器的概念是,对象的某些字段(或属性)发生更改时,所有“已注册”侦听器都将收到“通知”,并将新值复制到其字段中。 然而,它不是一种不必要的复杂设计吗? 下面是一个简单的建议,用于解决直接值指向和装箱(如果需要)的问题。 例如,对于字符串字段: public class StringBox { protected String value; public String getValue() { return value; } public void setValueAtomic(S

侦听器的概念是,对象的某些字段(或属性)发生更改时,所有“已注册”侦听器都将收到“通知”,并将新值复制到其字段中。 然而,它不是一种不必要的复杂设计吗? 下面是一个简单的建议,用于解决直接值指向和装箱(如果需要)的问题。 例如,对于字符串字段:

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个副本以及每次更改 或者在该字段中,将调用一个firePropertyChange,在所有侦听器上的循环中调用5次。 现在我明白了,为什么Eclipse或Netbeans IDE在性能差的笔记本电脑上运行速度非常慢,而且是在akku上运行的。
所以问题是,为什么人们在编程中使用监听器呢?

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

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


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

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

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

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

侦听器的概念是,对象的某些字段(或属性)发生更改时,所有“已注册”侦听器都将收到“通知”,并将新值复制到其字段中

我认为这个前提是错误的。我喜欢使用监听器,一般来说是观察者模式,但从来没有这样使用过

您可能希望在单击按钮时执行操作。例如,将一些文本打印到控制台。与其对每个监听器不断地轮询按钮进行更改,相反,如果按钮调用监听器,效率会更高

即使在单击按钮的帧期间,您有一个变量
isClicked
的引用,该变量是
true
,您也必须经常与每个侦听器一起检查
if(isClicked){…}

侦听器的概念是,对象的某些字段(或属性)发生更改时,所有“已注册”侦听器都将收到“通知”,并将新值复制到其字段中

我认为这个前提是错误的。我喜欢使用监听器,一般来说是观察者模式,但从来没有这样使用过

您可能希望在单击按钮时执行操作。例如,将一些文本打印到控制台。与其对每个监听器不断地轮询按钮进行更改,相反,如果按钮调用监听器,效率会更高


即使在单击按钮的帧期间有一个变量
isClicked
的引用,它是
true
,您也必须经常与每个侦听器一起检查
if(isClicked){…}

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

电子游戏是一个很好的例子,你可以使用可观察的模式,但有无数的例子。我参与了一场比赛,那里到处都是活动。其中一个事件是暂停事件。首先,我会手动通知所有需要了解暂停事件的对象、每个敌人和投射物以及音乐等。。我一直这样做是因为在游戏的这一部分添加可观察模式的成本和复杂性。但是过了一段时间,随着列表的增长,手动通知所有对象变得太困难了。所以我咬紧牙关,实现了可观察的模式。这对降低我的代码的复杂性有总体影响。使用可观察模式,任何需要被通知暂停事件的对象都会自行注册,以便在该事件发生时被通知

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