Design – How to best model an application’s settings

designobject-oriented-designsettings

My application has a configuration file and a "Settings" window. When the user confirms the changes in this window they are applied and written to the config file.

These settings are often changed and referenced throughout my program. I'm trying to figure out how to model the accessing and manipulating of these settings. On the one hand, I can't reference the GUI elements directly, that just seems like very bad practice. On the other hand I can't keep reading and writing to the config file because I don't want certain changes to settings to persist, e.g. the current username of the user logged in needs to be stored somewhere; I can't store it in the config file because I don't want the application to "remember" the user having accessed the system.

So is the solution to have a ConfigObj object, containing all the settings of the program, which is is accessible to all modules of the codebase? Is this a common solution?

But there is a problem which I don't know how to solve, demonstrated in the following scenario:

  1. Program starts, the ConfigObj object is initialised with the config file.
  2. User opens the "Settings" window. The GUI controls are populated with the values from the ConfigObj.
  3. One of the values in the "Settings" window is "COM Port", and if the user changes it and clicks "Save Settings" its value will be written to ConfigObj as well as the config file.
  4. The user closes the "Settings" window and opens another window "Find USB Port". This window finds an available COM port and assigns it to ConfigObj.Port. This change is rather temporary and isn't written to the config file, but now the global-wide selected port for the application is set to this, and other functions depend on this value.
  5. Now the user opens the "Settings" window again: the program should display the current settings of the program, i.e. what's in ConfigObj, but how does it know to do this instead of populating from the config file as in Step 1?

I suppose I could compare all values between the config file and ConfigObj, but is there a more correct way? What's the cleanest way to handle application-wide configuration?

Best Answer

Given that your application needs that kind of complexity, then here are my 5 cents (I will use Java code):

Settings are split in two categories acording to whether or not they take immediate effect when they are altered.

  • dynamic: have an immediate effect in the application's behavior
  • static: don't have an immediate effect in the application's behavior and only take effect on application restart, or on config reload.

The scope of altering a setting can be:

  • memory
  • disk
  • memory and disk

I think the Configuration object should implement this interface:

import java.util.List;
import java.util.Map;

public interface Configuration {
    // key is the name of a setting
    public void reload(); // reloads from disk without restarting app 
    public String getValue(String key); // gets value of setting identified by key
    public String getOldValue(String key); // gets old value of setting identified by key
    public String setValueToMemory(String key); // alters value of setting identified by 
                                                // key only in memory (will be lost after reload or restart)
    public String setValueToMemoryAndDisk(String key); //alters value of setting identified by key 
                                                       //both in memory and disk (will persist after reload or restart)
    public String isDirty(String key); // indicates whether or not this setting is "dirty", 
                                       // meaning it's value is different from disk.
    public Setting getSetting(String key); // return setting metadata
    public void dump(); // prints all key-value pairs
    public List<Setting> getSettings(); // gets a list of all settings (metadata)
    public Map<String,String> getValues(); // gets a map with key-value pairs 
}

In order for the Config Window to be able to visually indicate whether a setting is dynamic or static, a list of Setting objects should exist

public interface Setting {
    public String getName();
    public String setName(String name);
    public String getTag();
    public String setTag(String tag);
    public boolean isDynamic();
}
Related Topic