Create a Map where the key is Class<?> and the value is an expression (lambda or similar). Consider:
Map<Class,Runnable> doByClass = new HashMap<>(); doByClass.put(Foo.class, () -> doAClosure(this)); doByClass.put(Bar.class, this::doBMethod); doByClass.put(Baz.class, new MyCRunnable()); // of course, refactor this to only initialize once doByClass.get(getClass()).run();
If you need checked exceptions than implement a FunctionalInterface that throws the Exception and use that instead of Runnable.
Here's a real-word before-and-after showing how this approach can simplify code.
The code before refactoring to a map:
private Object unmarshall( final Property<?> property, final Object configValue ) { final Object result; final String value = configValue.toString(); if( property instanceof SimpleDoubleProperty ) { result = Double.parseDouble( value ); } else if( property instanceof SimpleFloatProperty ) { result = Float.parseFloat( value ); } else if( property instanceof SimpleBooleanProperty ) { result = Boolean.parseBoolean( value ); } else if( property instanceof SimpleFileProperty ) { result = new File( value ); } else { result = value; } return result; }
The code after refactoring to a map:
private final Map<Class<?>, Function<String, Object>> UNMARSHALL = Map.of( SimpleBooleanProperty.class, Boolean::parseBoolean, SimpleDoubleProperty.class, Double::parseDouble, SimpleFloatProperty.class, Float::parseFloat, SimpleFileProperty.class, File::new ); private Object unmarshall( final Property<?> property, final Object configValue ) { return UNMARSHALL .getOrDefault( property.getClass(), ( v ) -> v ) .apply( configValue.toString() ); }
This avoids repetition, eliminates nearly all branching statements, and simplifies maintenance.