Hi,
Can anyone suggest a workaround for the following problem? I have a
constant (static, final) whose value is calculated at runtime, when the
class is loaded. Because it isn't known at compile time, I can't use it in
a switch statement. But I'd like to.
public class StaticTest
{
public final int AAA = 1;
public final int BBB = 5 + 7;
public final int CCC = java.lang.String.class.getFields().length;
// ^-- just an example method
public void doSomething (int aIndex)
{
switch (aIndex)
{
case AAA: System.out.println("alpha"); break;
case BBB: System.out.println("bravo"); break;
case CCC: System.out.println("charlie"); break; // this line
doesn't compile
}
}
}
Convert your int index to an action object, which does the work for each
constant. IIRC this is the so-called Command Pattern. I've used it in
several occasions, both for primitive types (char, int, etc.) and
reference type (mostly Strings, but any type could do).
Below is an example how I'd implement it. You'll need a Map with ints as
keys (wrapped in Integer objects), and Action instances as values. In
the example I've chosen an interface, but Action could also be an
(abstract) class. Your switch now works by getting an Action object from
the Map that matches anIndex and call its method to do something.
import java.util.HashMap;
import java.util.Map;
public class CommandExample {
private static interface Action {
public void doSomething();
}
public static final int AAA = 1;
public static final int BBB = 5 + 7;
public static final int CCC =
java.lang.String.class.getFields().length;
private int someInstanceField;
private static Map actions;
public void doSomething(int anIndex) {
Action action = getAction(anIndex);
if (action != null) {
action.doSomething();
} else {
// default:
}
}
private static Action getAction(int anIndex) {
return (Action) getActions().get(new Integer(anIndex));
}
private static synchronized Map getActions() {
// lazily create the actions Map
if (actions == null) {
actions = new HashMap();
actions.put(new Integer(AAA), new Action() {
public void doSomething() {
System.out.println("alpha");
}
});
actions.put(new Integer(BBB), new Action() {
public void doSomething() {
System.out.println("bravo");
}
});
actions.put(new Integer(CCC), new Action() {
public void doSomething() {
System.out.println("charlie");
}
});
}
return actions;
}
}
You can easily extend it by adding additional methods to the Action
interface. These methods can have parameters. For instance, when you
need to access an instance field, you could pass this to the method:
private static interface Action {
public void doSomething();
public int calcSomething(CommandExample thiz);
}
You then would have to implement the calcSomething method for each Action:
private static synchronized Map getActions() {
// lazy create actions Map
if (actions == null) {
actions = new HashMap();
actions.put(new Integer(AAA), new Action() {
public int calcSomething(CommandExample thiz) {
return thiz.someInstanceField + 1;
}
public void doSomething() {
System.out.println("alpha");
}
});
// ... etcetera
Applying it would look like this:
public int calcSomething(int anIndex) {
Action action = getAction(anIndex);
if (action != null) {
return action.calcSomething(this);
} else {
// default:
return 0;
}
}
public static void main(String[] args) {
CommandExample example = new CommandExample();
example.doSomething(12);
System.out.println(example.calcSomething(1));
}
--
Regards,
Roland de Ruiter
` ___ ___
`/__/ w_/ /__/
/ \ /_/ / \