A good design should follow (among the others) the Open-Closed Principle: you should be able to add new functionalities without amend the existing code.
In order to have a playground where we can continue this discussion
, let’s define a scenario: we have several strategies to validate a string(param1) and we use a factory method in order to obtain the correct strategy implementation from time to time.
A common implementation of the factory method in this scenario can be:
if (type.equals(MyTypes.BOOLEAN)) {
return new BooleanValidator(param1);
} else if (type.equals(MyTypes.NUMBER)) {
return new NumberValidator(param1);
} else if (type.equals(MyTypes.DATE)) {
return new DateValidator(param1);
}
Obviously the if with multiple branches smells to us like a three-days old sandwich in our lunch-bag
, and we are also breaking the OCP!!
If we are in JavaLand(but this is also valid for other languages such -for example- C#) reflection can help us: if we define that all the classes that implement a specific behaviour(in our example the validation of a string) stay in a defined package (let’s say P), the factory method can simply(?)� go through the classes in P and instantiate what we need thanksto the� reflection mechanism.
But..is that so simple ??
final Map validators = new HashMap();
[some code that through reflection populate the map with all the classes within the package P and assign the right key for each entry] [...]
try {
Class theClass = validators.get(type);
Constructor constructor = theClass.getConstructor(new Class[]{CelonaDataTypes.class, String.class});
ValidatorInterface validator = (ValidatorInterface)constructor.newInstance(new Object[]{param1);
return validator;
} catch (InvocationTargetException e) {
throw new MyException(e.getMessage());
} catch (NoSuchMethodException e) {
throw new MyException(e.getMessage());
} catch (InstantiationException e) {
throw new MyException(e.getMessage());
} catch (IllegalAccessException e) {
throw new MyException(e.getMessage());
}
The latter solution from a technical point of view is smart and elegant, but sounds to me terribly unclear.
The (annoying) necessity of managing all the checked expections in JavaLand increase the white noise around the code. Furthermore the reflection APIs in Java are not so clear: if I find this code while I’m trying to learn a new code base a big WTF will appear over my head
!!
The former solution instead is surely a bit tacky, but is probably more readable (but, yes, I’m breaking the OCP and therefore I’m out of law). The second moreover looks a bit like a candy for my ego: my geek side will be really happy….but what about customers and the other team members ?
I’m not totally sure if my point of view is reasonable(any feedback is appreciated
) or if I’m simply scared by the increased complexity of my code.
But while I can agree that the first is nearly simplicistic, I’m not sure that the second is enough simple.
And if it’s not simple, I really don’t like it…