【问题标题】:trying to change values with firepropertychange,propertychangesupport尝试使用 firepropertychange、propertychangesupport 更改值
【发布时间】:2019-01-10 15:24:14
【问题描述】:

我使用 propertychangesupport、propertychange 和 fireproperty change 编写 java 程序,现在它可以工作,但根本不是这样当我把它放在while条件下时,改变它只是想退出循环,

公共类主{

public static void main(String[] args) {
        CLI cli = new CLI(System.in,System.out);
        Server server = new Server(34567);
        cli.addPropertyChangeListener(server);
        new Thread(cli).start();
}

}

公共类 CLI 实现 Runnable{

private Scanner scanner;
private String userInput;
private PropertyChangeSupport pcs;
private Boolean serverIsRunning;

public CLI(InputStream in, OutputStream out){
    this.scanner = new Scanner(in);
    pcs = new PropertyChangeSupport(this);
    serverIsRunning = false;
}


@Override
public void run() {

    while (true) {
        System.out.println("pls enter your command:");
        userInput = scanner.nextLine().trim().toUpperCase();
        switch (userInput) {
            case "START":
                if (!serverIsRunning)   {
                    pcs.firePropertyChange(userInput, null, "START");
                    new Thread(new Server(34567)).start();
                    serverIsRunning = true;
                } else {
                    System.out.println("server is already running");
                }
                break;
            case "SHUTDOWN":
                if (serverIsRunning) {
                    pcs.firePropertyChange(userInput, null, "SHUTDOWN");
                    serverIsRunning = false;
                } else {
                    System.out.println("server is not running");
                }
                break;
        }
    }
}

public void addPropertyChangeListener(PropertyChangeListener pcl){
    this.pcs.addPropertyChangeListener(pcl);
}

public void removePropertyChangeListener(PropertyChangeListener pcl){
    this.pcs.removePropertyChangeListener(pcl);
}

}

公共类Server实现Runnable、PropertyChangeListener {

private int port;
private ServerSocket server;
private String userInput = "";
private Boolean serverIsRunning;

public Server(int port) {
    this.port = port;
    serverIsRunning = true;
}

public void propertyChange(PropertyChangeEvent evt) {
        userInput = evt.getNewValue().toString();
        switch (userInput) {
            case "START":
                System.out.println("Starting server...");
                serverIsRunning = true;
                break;
            case "SHUTDOWN":
                serverIsRunning = false;
                break;
        }
    }


@Override
public void run() {
    try {
        server = new ServerSocket(port);
    } catch (IOException e) { }

    while (serverIsRunning) {
        try {
            new Thread(new Client(server.accept())).start();
        } catch (IOException e) { }
    }

    try {
        server.close();
        System.out.println("shutdown");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

【问题讨论】:

  • “它只是想摆脱循环”。 while(true),你期待什么?
  • 使用侦听器结构的主要目的之一是通知对象状态更改,因此不需要或使用 while 循环来轮询状态更改。正确的解决方案是摆脱那个while循环
  • 我不是指主要的那个
  • 我的意思是Listener类中的那个
  • @HovercraftFullOfEels 你是对的,我很抱歉。 @Koby,您的 while 循环将无限运行,因为 run() 将输入一次并且条件将始终为真。如果您在listenToChange = evt.getNewValue().toString(); 之后添加对run() 的调用,这可能会起作用,但如前所述,这只是糟糕的设计,因为您最终将有许多线程运行无限循环,请遵循气垫船答案的建议以充分利用豆类

标签: java inotifypropertychanged


【解决方案1】:

再一次,使用监听器设计模式的主要目的是避免必须使用 while 循环来不断轮询状态变化,而是让监听器和监听器支持协同工作以通知您何时对象的状态发生变化。

其他问题:

  • Bean 应保存已侦听或“绑定”字段
  • bean 本身应在状态更改位置调用fireXxx 方法,而不是您的任何其他类。
  • 侦听器不应具有或不需要while (true) 循环。它应该做的就是监听并响应 Bean 中的状态变化,不多也不少。

例如说你的 bean 看起来像这样:

public class Bean2 {
    // constant for the property change name
    public static final String STATE = "state";
    private PropertyChangeSupport pcs;

    // this is the "bound" field
    private String state = "";

    public Bean2() {
        pcs = new PropertyChangeSupport(this);
    }

    public String getState() {
        return state;
    }

    // notify listeners within the setter
    public void setState(String state) {
        String oldValue = this.state;
        String newValue = state;
        this.state = state;
        pcs.firePropertyChange(STATE, oldValue, newValue);
    }

    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(propertyName, listener);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(listener);
    }

    // method to remove... 

}

那么你的监听器可以这么简单:

public class Listener2 implements PropertyChangeListener {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println("From listener: state change -- new state: " + evt.getNewValue());
        // this code will obviously need to do more...
    }
}

并像这样使用:

public static void main(String[] args) {
    Bean2 bean = new Bean2();
    Listener2 listener = new Listener2();
    bean.addPropertyChangeListener(Bean2.STATE, listener);

    Scanner scanner = new Scanner(System.in);
    String text = "";
    while (!text.equalsIgnoreCase(EXIT)) {
        System.out.print("Enter text or \"EXIT\" to quit: ");
        text = scanner.nextLine();
        if (!text.equalsIgnoreCase(EXIT)) {
            bean.setState(text);
        }
    }
    scanner.close();
}

看,没有while循环,没有从bean调用fireXxx


关于您的编辑,我仍然不能 100% 确定您的整个程序设置,但可能是这样的:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class MyServer2 {
    private static final String EXIT = "exit";
    public static final int PORT = 4444;
    private ServerSocket server;

    public MyServer2() throws IOException {
        server = new ServerSocket(PORT);
    }

    public void beanChanged(String text) {
        // *** not sure what you want to do with this text 
        // *** other than to check that it != EXIT
        if (!text.equalsIgnoreCase(EXIT)) {
            try {
                new Thread(new Client(server.accept()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            // System.exit(0); // ????
        }
    }

    public static void main(String[] args) {
        MyServer2 server = null;
        try {
            server = new MyServer2();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Bean2 bean = new Bean2();
        Listener2 listener = new Listener2(server);
        bean.addPropertyChangeListener(Bean2.STATE, listener);

        Scanner scanner = new Scanner(System.in);
        String text = "";
        while (!text.equalsIgnoreCase(EXIT)) {
            System.out.print("Enter text or \"EXIT\" to quit: ");
            text = scanner.nextLine();
            if (!text.equalsIgnoreCase(EXIT)) {
                bean.setState(text);
            }
        }
        scanner.close();
    }

}

public class Bean2 {
    // constant for the property change name
    public static final String STATE = "state";
    private PropertyChangeSupport pcs;

    // this is the "bound" field
    private String state = "";

    public Bean2() {
        pcs = new PropertyChangeSupport(this);
    }

    public String getState() {
        return state;
    }

    // notify listeners within the setter
    public void setState(String state) {
        String oldValue = this.state;
        String newValue = state;
        this.state = state;
        pcs.firePropertyChange(STATE, oldValue, newValue);
    }

    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(propertyName, listener);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(listener);
    }

    // method to remove...

}

public class Listener2 implements PropertyChangeListener {
    private MyServer2 myServer2;

    public Listener2(MyServer2 myServer2) {
        this.myServer2 = myServer2;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        // notify server by calling its public method with new value
        myServer2.beanChanged((String) evt.getNewValue());
    }
}

public class Client implements Runnable {
    private Socket socket;

    public Client(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        // TODO finish coding

    }

}

但这仍然让人感到尴尬。请注意,我通常会将我的代码放到accept() 一个新客户端的线程中,因为它会阻塞代码,例如:

new Thread(() -> {
    while (true) {
        try {
            new Thread(new Client(server.accept()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

【讨论】:

  • 好的,我读了这段代码,但如果我需要运行一个需要等待新客户端的服务器,它不会帮助我 while (!listenToChange.equals("exit") { try { new Thread(new Client(server.accept()); } catch (IOException e) { } } 像这样
  • 再次摆脱 while 循环。相反,上面的代码应该在propertyChange 方法中调用。
  • 但是我需要在不同的线程上运行它,所以我需要重写 run 方法并将它放在那里,这不是问题,因为那是在 run 方法上
  • @koby:上面的代码适用于您在问题中发布的问题和代码。如果您需要它在不同的情况下工作,您需要发布一个足以反映新情况的minimal reproducible example。对于未显示的代码,我们无能为力。
  • 如果您现在可以告诉我如何摆脱 while 循环,我将编辑代码,谢谢
猜你喜欢
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 2022-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多