Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javafx and the Observer pattern - updating a UI

Tags:

javafx

I am trying to implement the Observer pattern in a JavaFx application. I've never asked a question here but this is driving me a bit crazy.

Essentially I'm trying to use the Observer pattern to monitor a class that's parsing a file of phone numbers, and update the UI automatically as the file is parsed.

Before I get to my questions, here is my code:

Abstract class Observer.java

public abstract class Observer 
{
   public PhoneBook numbers;

   public abstract void update();
}

I have a class that implements this:

public class PhoneBookObserver extends Observer {

    public PhoneBookObserver(PhoneBook numbers)
    {
        this.numbers = numbers;
        this.numbers.attach(this);
    }

    @Override
    public void update()
    {
        System.out.println(""NUMBER - : " + numbers.GetNumbers());

    }
}

In the class doing the parsing, I've created a new PhoneBookObserver

public PhoneBook ParsePhoneBook() 
{   
    PhoneBook nums= new PhoneBook();
    PhoneBookObserver p = new PhoneBookObserver(nums);

    // ... Parsing of file - works fine

   return nums;
}

Currently this runs and my println from update() in PhoneBookObserver is output.

My questions are:

  • Can the update method of PhoneBookObserver update my UI for me? How would it access JavaFx elements in my controller?
  • Can I just make my controller an observer, override update() and use that to update my UI elements from within my controller? Is that bad?
like image 673
timbo baggins Avatar asked Sep 02 '25 09:09

timbo baggins


1 Answers

To directly answer your question, I would probably implement the Observer as an inner class in the controller. Then it has access to everything in the controller.

Assuming here PhoneBook defines a method of the form

public List<PhoneNumber> getPhoneNumbers() ;

then you could do:

public class Controller {

    @FXML
    private ListView<PhoneNumber> phoneNumberList ;

    private PhoneBook numbers = new PhoneBook() ; // or initialize from elsewhere

    public void initialize() {
        numbers.attach(new PhoneBookObserver(numbers));
        // ...
    }

    private class PhoneBookObserver extends Observer {

        PhoneBookObserver(PhoneBook numbers) {
            this.numbers = numbers ;
        }

        @Override
        public void update() {
            phoneNumberList.getItems().setAll(numbers.getPhoneNumbers());
        }
    }
}

Note that in

public abstract class Observer 
{
   public PhoneBook numbers;

   public abstract void update();
}

the field numbers really serves no purpose, as the only method doesn't use it. So you could remove it (subclasses can define such a field if they need). Then you may as well make it an interface, and since it only has one method, it's a @FunctionalInterface:

@FunctionalInterface
public interface Observer {
    public void update() ;
}

and now it can be implemented with a lambda expression, so the implementation is so thin that you basically stop having any issues with "accessing the UI":

public class Controller {

    @FXML
    private ListView<PhoneNumber> phoneNumberList ;

    private PhoneBook numbers = new PhoneBook() ; // or initialize from elsewhere

    public void initialize() {
        numbers.attach(() -> phoneNumberList.getItems().setAll(numbers.getPhoneNumbers());
        // ...
    }

}

Finally, note that JavaFX Properties and observable lists basically already provide an implementation of the observer pattern, so you're pretty much reinventing the wheel here. You could just have

public class PhoneBook {

    private final ObservableList<PhoneNumber> numbers;

    public ObservableList<PhoneNumber> getPhoneNumbers() {
        return numbers ;
    }
}

and then

public class Controller {

    @FXML
    private ListView<PhoneNumber> phoneNumberList ;

    private PhoneBook numbers = new PhoneBook() ; // or initialize from elsewhere

    public void initialize() {
        phoneNumberList.setItems(numbers.getPhoneNumbers());
    }

}

and the list view will observe the (already-observable) list of numbers for you. There is no real need for your Observer or PhoneBookObserver.

like image 189
James_D Avatar answered Sep 05 '25 00:09

James_D