简体   繁体   中英

trying to change values with firepropertychange,propertychangesupport

i writing java program using propertychangesupport,propertychange and fireproperty change, now its working but not at all case, when ii change the value and printed it its working, but when i tried to do a while loop on the spesipic class that listen to change it just wond get out the loop when i put it in the while condition,

public class Main {

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();
}

}

public class CLI implements 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);
}

}

public class Server implements 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();
    }
}

}

Again a main purpose of using a listener design pattern is to avoid having to use a while loop to continually poll for state change and instead have the listener and listener support work together to notify you when the state of an object changes.

Other issues:

  • The Bean should hold the listened-to or "bound" field
  • The bean itself should call the fireXxx method at the location of change of state, not any of your other classes.
  • The listener should not have or need a while (true) loop. All it should do is listen and respond to state changes in the Bean, nothing more and nothing less.

For example say your bean looked like this:

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... 

}

Then your listener could be as simple as:

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...
    }
}

and used like so:

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();
}

See, no while loop, no calling fireXxx out of the bean


Regarding your edits, I'm still not 100% sure of your entire program set up, but perhaps something along these lines:

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

    }

}

But this still feels awkward. Note that I usually will put my code to accept() a new client in its own thread, since it is blocking code, something like:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM