3

Can someone give me the design of how to maintain all the hardcoded values sepratly.

I'm currently using some design patterns, are these fine? And is there any thing more I can do for better design of my applicaiton code.

The design patters I use are (My application is having multiple screens similar wizard):

  1. Using a ResourceBundle for all the strings, which are visible to user (for internationalizaiton)
  2. Using the properties file to save all the values of a particular screen to make accessible for other screens (These values are for internal purpose of program, not visible to user). I'm continuously loading these properties in program at various places to get the updated values like, while going to second screen (Panel) from first screen, to get the values of first screen in second screen.
  3. I'm Thinking to externalize the logging messages using Resource bundles.

Is there any better design approaches? to seperate from program code, A. the "messges visible to user", B. log messages, C. Usability values (screen sizes, Fonts, etc), values user has input in the screens, directory/file paths...

merlachandra
  • 376
  • 2
  • 17

4 Answers4

2

I would check out the Java Preferences API, which allows you to store system-wide defaults, per-user defaults and make use of hard-coded defaults in the absence of configured values.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
2

Resource bundles for I18N are exactly the right thing. Properties files do well, but you'll have to repackage and redeploy if you change them. It's often more flexible to put other items in a database, because you can change the app by pushing data without repackaging and redeploying.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • I'm using ResourceBundle for i18n, this is fine. On the otherside, I'm using the properties files for storing the inputs values which user has input, But this needs loading the properties file just before we use. Loading is required since the contents are changed during run time. Is there any alternative to the properties file, to avoid the loading at many points? – merlachandra Oct 17 '12 at 11:53
  • I think Database will work, but Is there any other option available for my above question apart from database approach? – merlachandra Oct 17 '12 at 11:57
  • Properties are read-only. If you need to change at runtime, use a database. – duffymo Oct 17 '12 at 11:57
  • Ho is it? So using properties files for writing runtime changes is not a good approach, Right? – merlachandra Oct 17 '12 at 12:00
2

Your GUI should have a complete data model. This model can read I18n resource files and regular resource files to populate part of the model. A data model is one or more Java classes that hold the data important to your application while the application is running.

As an example, here is a stopwatch GUI that I created.

enter image description here

And here's the data model class associated with the stopwatch GUI.

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.DefaultTableModel;

public class StopwatchModel {

    protected boolean isSplitTime;

    protected long startTime;

    protected long endTime;

    protected DefaultTableModel tableModel;

    protected List<Long> splitTimes;

    protected String[] columnNames = {"", "Increment", "Cumulative"};

    public StopwatchModel() {
        this.splitTimes = new ArrayList<Long>();
        this.isSplitTime = false;
        this.startTime = 0;
        this.endTime = 0;
        setTableModel();
    }

    public void resetTimes() {
        this.splitTimes.clear();
        this.isSplitTime = false;
        this.startTime = 0;
        this.endTime = 0;
    }

    public boolean isSplitTime() {
        return isSplitTime;
    }

    public long getStartTime() {
        return startTime;
    }

    public long getEndTime() {
        return endTime;
    }

    public long getLastSplitTime() {
        int size = splitTimes.size();
        if (size < 1) {
            return getStartTime();
        } else {
            return splitTimes.get(size - 1);
        }
    }

    public long getPenultimateSplitTime() {
        int size = splitTimes.size();
        if (size < 2) {
            return getStartTime();
        } else {
            return splitTimes.get(size - 2);
        }
    }

    public DefaultTableModel getTableModel() {
        return tableModel;
    }

    public int getTableModelRowCount() {
        return tableModel.getRowCount();
    }

    public void clearTableModel() {
        tableModel.setRowCount(0);
    }

    public int addTableModelRow(long startTime, long previousSplitTime, 
            long currentSplitTime, int splitCount) {
        String[] row = new String[3];

        row[0] = "Split " + ++splitCount;
        row[1] = formatTime(previousSplitTime, currentSplitTime, false);
        row[2] = formatTime(startTime, currentSplitTime, false);

        tableModel.addRow(row);

        return splitCount;
    }

    public void setStartTime() {
        if (getStartTime() == 0L) {
            this.startTime = System.currentTimeMillis();
        } else {
            long currentTime = System.currentTimeMillis();
            int size = splitTimes.size();
            if (size > 0) {
                long splitTime = splitTimes.get(size - 1);
                splitTime = splitTime - getEndTime() + currentTime;
                splitTimes.set(size - 1, splitTime);
            }
            this.startTime = currentTime - getEndTime() + getStartTime();
        }
    }

    protected void setTableModel() {
        this.tableModel = new DefaultTableModel();
        this.tableModel.addColumn(columnNames[0]);
        this.tableModel.addColumn(columnNames[1]);
        this.tableModel.addColumn(columnNames[2]);
    }

    public void setSplitTime() {
        this.splitTimes.add(System.currentTimeMillis());
        isSplitTime = true;
    }

    public void setEndTime() {
        Long split = System.currentTimeMillis();
        if (isSplitTime) {
            this.splitTimes.add(split);
        }
        this.endTime = split;
    }

    public String formatTime(long startTime, long time, boolean isTenths) {
        long elapsedTime = time - startTime;

        int seconds = (int) (elapsedTime / 1000L);

        int fraction = (int) (elapsedTime - ((long) seconds * 1000L));
        fraction = (fraction + 5) / 10;
        if (fraction > 99) {
            fraction = 0;
        }
        if (isTenths) {
            fraction = (fraction + 5) / 10;
            if (fraction > 9) {
                fraction = 0;
            }
        }


        int hours = seconds / 3600;
        seconds -= hours * 3600;

        int minutes = seconds / 60;
        seconds -= minutes * 60;

        StringBuilder builder = new StringBuilder();

        builder.append(hours);
        builder.append(":");
        if (minutes < 10) builder.append("0");
        builder.append(minutes);
        builder.append(":");
        if (seconds < 10) builder.append("0");
        builder.append(seconds);
        builder.append(".");
        if ((!isTenths) && (fraction < 10)) builder.append("0");
        builder.append(fraction);

        return builder.toString();
    }

}

The model would also contain transient data that gets you from one JPanel to the next JPanel. Transient data is data that only needs to exist for a short period of time, usualy as long as the GUI is active. It doesn't have to be saved after the GUI is exited.

The reason that you use a model / view to build a GUI is separation of concerns. The rest of your application accesses the data model, rather than any GUI components.

Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
0

For "Usability values" I've used a singleton pattern. Create a class called Configuration and then a static method, Configuration.getConfig() that calls the private constructor. All of the objects that your program needs can be stored as fields in this class. The constructor loads the values using the preferences API. I posted some example code for this in a recent S.O. post.

The advantage of placing all of your configuration data in a single class which is responsable for loading it is that now the method in which you are storing this data is abstracted away from the rest of your code. If you decide to use a database or ResourceBundle for storage, only Configuration needs to change.

Community
  • 1
  • 1
Thorn
  • 4,015
  • 4
  • 23
  • 42