1
\$\begingroup\$

I am working in JavaFX and I created util class which is responsible for creating new window. I called this class WindowUtil. Depending on the button that was clicked I want to:

  1. Open new window

  2. Send some data to controller of this window (this is optional)

The problem is that code responsible for opening a new window is always the same among overloaded methods so I'd like to somehow write this code only once.

Below I present these methods. Some of them are overloaded and some of them are not.

public static void loadWindow(String path, String appName) {
    try {
        Stage subWindow = new Stage();
        subWindow.setResizable(false);
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(WindowUtil.class.getResource(path).openStream());
        Scene scene = new Scene(parent);
        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void loadWindowAndSendData(String path, String appName, ConnectionData connectionData) {
    try {
        Stage subWindow = new Stage();
        subWindow.setResizable(false);
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(WindowUtil.class.getResource(path).openStream());
        ConnectionDataProvider controller = loader.getController();
        controller.getConnectionData(connectionData);
        Scene scene = new Scene(parent);
        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}


public static void loadWindowAndSendData(String path, String appName, ConnectionData connectionData, Data data,
        OrderedItemsData orderedItemsList) {
    try {
        Stage subWindow = new Stage();
        subWindow.setResizable(false);
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(WindowUtil.class.getResource(path).openStream());
        ProcessingController processingController = (ProcessingController) loader.getController();
        processingController.getData(connectionData, data, orderedItemsList);
        Scene scene = new Scene(parent);
        processingController.startConnection();
        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void loadWindowAndSendData(String path, String appName, StoredItem rowData,
        OrderedItemsData orderedItemsData) {
    try {
        Stage subWindow = new Stage();
        subWindow.setResizable(false);
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(WindowUtil.class.getResource(path).openStream());
        SpecifyQuantityController quantityController = (SpecifyQuantityController) loader.getController();
        quantityController.getData(rowData, orderedItemsData);
        Scene scene = new Scene(parent);
        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public static void loadWindowAndSendData(String path, String appName, Data data) {
    try {
        Stage subWindow = new Stage();
        subWindow.setResizable(false);
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(WindowUtil.class.getResource(path).openStream());
        DataProvider controller = loader.getController();
        controller.getData(data);
        Scene scene = new Scene(parent);
        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

As you can see:

-first 5 lines of each method are always the same,

-last 4 lines of each method are also always the same.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

You correctly identified the part that differs among these methods, so next step is to exclude this part. Its role is to initialize the Parent instance to be set on subWindow. This instance can just be passed as argument to the extracted method:

public static void loadWindow(String appName, Parent parent) {
  Objects.requireNonNull(parent);

  Stage subWindow = new Stage();
  subWindow.setResizable(false);
  subWindow.initModality(Modality.APPLICATION_MODAL);
  Scene scene = new Scene(parent);
  subWindow.setScene(scene);
  subWindow.setTitle(appName);
  subWindow.show();
}

Now you need just to instantiate parents respectively and call loadWindowAndSendData with them.

\$\endgroup\$
1
\$\begingroup\$

Basically, the only difference is, that one time you use the controller for something and the other time you don't.

Not knowing what the controller does with the connection data makes it a bit difficult, but if it is equivalent to call controller.getConnectionData(connectionData); at the end of the process, I'd refactor like this:

// you can probably find a more useful return value than Object
public static Object loadWindow(String path, String appName) {
    try {
        Stage subWindow = new Stage();
        subWindow.setResizable(false);
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(FxinstMain.class.getResource(path).openStream());
        Object controller = loader.getController();
        Scene scene = new Scene(parent);
        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
        return controller;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

Caller 1:

loadWindow(path, appName);

Caller 2:

ConnectionDataProvider controller = (ConnectionDataProvider ) loadWindow(path, appName);
controller.getConnectionData(connectionData);

Or going back to principles: separation of concerns: load the window, return the controller is enough for a single method. Init data seems not to belong in there.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.