Friday, February 04, 2005

Unusual use for enum

In JDK 5, enum isn't just a collection of static instances, it is also conceptually a list and a map (although it does not implement these interfaces). To wit:

enum Hierarchy {
    ACCOUNT(Preferences.userNodeForPackage(Account.class)),
    LOCAL(Preferences.userNodeForPackage(Local.class)),
    SYSTEM(Preferences.systemNodeForPackage(System.class)),
    GLOBAL(Preferences.systemNodeForPackage(Global.class));

    private final Preferences preferences;

    Hierarchy(final Preferences preferences) {
        this.preferences = preferences;
    }

    public Preferences getPreferences() {
        return preferences;
    }

    private static final class Account { }
    private static final class Local { }
    private static final class System { }
    private static final class Global { }
}

This creates a hierachy of preferences. Finding a match is simple:

public String get(String key, String def) {
    for (final Hierarchy hierarchy : Hierarchy.values()) {
        final String preference = hierarchy.getPreferences().get(key,
                null);

        if (null != preference) return preference;
    }

    return def;
}

As the for loop iterates over the values of the enumeration in order of declaration, this ensures they individual preferences are searched in order. In effect, they are overlaid. And the encapsulation is particularly elegant.

An immediate design decisions lays ahead: Should methods such as get(String, String) and its ilk be static members of the enumeration, or should the enumeration be a private class inside a utility class which has the various get/put pairs?

UPDATE: In the original posting, I mistakenly assigned system nodes for ACCOUNT and LOCAL instead of user nodes. Fixed.

UPDATE: Oops! Preferences are stored per-package, not per-class. My clever trick still works, provided I make packages out of the categories rather than inner classes. I lose the encapsulation, but keep the technique. Unless I can create packages on the fly at run-time.

No comments: