Question

I have a project that is in need of refactoring. It is a Java desktop SWT/JFace application with approximately 40 GUI components with major components controlling the lifecycle of minor components. I want to have good modular design with low coupling, but I can't find a way to avoid global state without having very long constructors.

For example, the current approach to internationalization in the software is something like:

public class Main {
    public static void main(String[] args) {
        MyMessages.loadMessages();
    }
}
public class MyMessages {
    private static ResourceBundle messages;
    public static void loadMessages() {
        messagesBundle = ResourceBundle.getBundle("messages", "en");
    }

    public static void getMessage(String m) {
        return messagesBundle.getString(m);
    }
}

public class SomeComponent extends Component() {
    public void init() {
        String textboxLabel = MyMessages.getMessage("someMessage");
    }
}

Other places in the code use singletons (for data models), which makes it hard to analyse dependencies as the codebase grows.

An alternative approach would be to make MyMessages stateful and pass the instance of it all the way through the hierarchy of GUI components. To me this seems messy, error-prone and not worth the hassle compared to the perceived benefit.

What other ways are there to design this in a way that:

  • Doesn't rely on what are essentially global variables.
  • Makes the dependency relationships explicit.
  • Doesn't clutter the code with lengthy constructors.

Should I consider dependency injection frameworks, or is there another approach that doesn't seem overkill for a small desktop application?

Was it helpful?

Solution

Should I consider dependency injection frameworks, or is there another approach that doesn't seem overkill for a small desktop application?

For a small desktop app, I would recommend using the dependency injection design pattern, but hold off on using an industrial-strength DI framework.

In your code, the message helper classes are OK, but your SomeComponent class is definitely not DI friendly:

public class SomeComponent extends Component() {
    public void init() {
        String textboxLabel = MyMessages.getMessage("someMessage");
    }
}

SomeComponent is now tied to MyMessages.

Instead use something like:

public class SomeComponent extends Component() {

    public void setTextBoxLabel(String value) {
        // implementation depends on requirements
    }

    public void init() {
        // do something with all the properties that were set
    }
}

Basically just add setters to your component. This the first part of DI. Make it so all your classes are loosely coupled and each class just trusts that someone is going to take care of setting all it's properties. No need for global state because everything a component needs is going to be injected into it.

Of course once you do this, your startup code is going to become a nightmare because you have to create all these objects and set all their properties and it's all tied into your application. At which point you start refactoring your startup code and create builders and/or factories which take care of creating the objects for you.

Let's say one of the components is initialized by a properties file. You create a builder that reads the properties file, instantiates the component, set the components properties and returns the instance. The component knows nothing about properties files. It just has some getters and setters which it knows will be set at startup.

Later on you decide to use XML as the file format - but for a different app, while still using properties file for the first app. No problem - create a new XML builder that reads the XML file and builds the component - but the actual GUI component remains unchanged because it is completely decoupled from how it gets initialized.

The key is to review creational design patterns and figure out which patterns (builder, factory etc) help you to reliably create your components while avoiding global state.

OTHER TIPS

I would use global state. Especially if you are re-using views. IMHO opinion there is nothing wrong with having some sort of lookup for the various components that are going to get heavy usage from all over the app.

Note that if you use a DI framework, then chances are going to be using some sort of global state implicitly (granted, this is implementation dependent on the DI framework). Considering Spring for example, the ApplicationContext is a global object that itself is going to keep various components around and/or manage the components' lifecycles, depending on the configuration for the various beans.

Having global components is not necessarily a bad thing. If the tradeoff is huge constructor signatures and passing references around, I'd take the global references (well I'd put them in some sort of Application object) any day.

How about using java logger api...in addition StreamHandler class can be extended and set the output stream to components. You can also track the messages and associated classes and methods.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top