问题
I have a Trigger Manager scenario where I delegate the triggers (in other-words subscribe triggers) to different handlers.
For now I have three handler types, I use a switch-case with enum (enum here is the handler type) to redirect to correct handler.
But my code seems not extensible, its not generic and it doesn't follow SOLID principle. Imagine if I need to have more handler
I will be eventually coming and editing my switch case code and I will have more cases where it affects the cyclomatic complexity of my code
Below is my exact code snippet
private static TriggerContext getTriggerContext(TriggerHandlerType triggerHandlerType) throws TriggerHandlerException {
switch (triggerHandlerType) {
case DASHBOARD_HANDLER:
triggerContext = new TriggerContext(new DashboardTriggerHandler());
return triggerContext;
case COMPONENT_HANDLER:
triggerContext = new TriggerContext(new ComponentTriggerHandler());
return triggerContext;
case WIDGET_HANDLER:
triggerContext = new TriggerContext(new WidgetTriggerHandler());
return triggerContext;
default:
LOGGER.error(MIS_CONFIGURED_REQUEST_IS_PROVIDED);
throw new TriggerHandlerException(TRIGGER_HANDLER_TYPE_GIVEN_IS_NOT_CONFIGURED_IN_THE_LIST_OF_TRIGGER_HANDLERS);
}
}
Can someone help me to enhance this code in-which I can make it more generic and avoid cyclomatic complexity and follow SOLID Principle along with some design pattern.
回答1:
I think you mean "make code more dynamic", and your problem comes from using objects as primitives.
Rather than switching on the enum object, your enum objects should contain the type to be instantiated:
enum TriggerHandlerType {
DASHBOARD {
@Override
TriggerHandler create() {
return new DashboardTriggerHandler();
}
},
COMPONENT_HANDLER {
//...
};
abstract TriggerHandler create();
}
getTriggerContext
can then call create()
to instantiate the handler:
private static TriggerContext getTriggerContext(TriggerHandlerType triggerHandlerType) throws TriggerHandlerException {
return new TriggerContext(triggerHandlerType.create());
}
回答2:
I am not sure about the overall design structure, but the switch can be replaced with a newHandler()
method on the enum.
private static TriggerContext getTriggerContext(TriggerHandlerType triggerHandlerType)
throws TriggerHandlerException
{
return new TriggerContext(triggerHandlerType.newHandler());
}
In the enum you would implement the method for each type enum as
enum TriggerHandlerType {
DASHBOARD_HANDLER
{
Handler newHandler() { return new DashboardHandler(); }
},
...;
abstract Handler newHandler();
}
回答3:
You could use a map of configurations for that:
// All your triggers classes should implement this interface
interface TriggerHandler {}
// For example:
public static class DashboardTriggerHandler implements TriggerHandler {
}
// Create your configuration
static Map<TriggerHandlerType, Class> contexts;
static {
contexts = new HashMap<>();
contexts.put(TriggerHandlerType.DASHBOARD_HANDLER, DashboardTriggerHandler.class);
contexts.put(TriggerHandlerType.COMPONENT_HANDLER, ComponentTriggerHandler.class);
contexts.put(TriggerHandlerType.WIDGET_HANDLER, WidgetTriggerHandler.class);
}
// Return your instance through reflection
public static TriggerContext getTriggerContext(TriggerHandlerType triggerHandlerType) throws TriggerHandlerException, IllegalAccessException, InstantiationException {
Class className = contexts.get(triggerHandlerType);
if (className == null) {
throw new TriggerHandlerException();
}
return new TriggerContext((TriggerHandler)className.newInstance());
}
来源:https://stackoverflow.com/questions/39044863/make-code-more-generic-in-java