19 February 2019

Set Of Responsability and IOC

I recently read this Pietro’s post about a possible adaptation of the “Chain of responsability” pattern: the “Set of responsability”. This is very similar to its "father" because each Handler handles the responsibility of a Request but in this case it doesn’t propagate the check of responsibility to other handlers. There is a responsibility without chain!

In this article I’d like to present the usage of this pattern in an IOC Container, where the Handlers aren’t added to the HandlerSet list but provided from the container. In this way you can add new responsibility to the system simply adding a new Handler in the container without changing other parts of implemented code (es. the HandlerSet), in full compliance with the Open closed principle.  

For coding I’ll use the Spring Framework (JAVA) because it has a good IOC Container and provides a set of classes to manage with that. Inversion of control principle and the Dependency Injection are first class citizens in the SpringFramework.

Here is the UML class diagram with 3 responsabilities X,Y,Z and a brief description of the solution adopted.

@Component
public class XHandler implements Handler {

    @Override
    public Result handle(Request request) {
       return ((RequestX) request).doSomething();
    }

    @Override
    public boolean canHandle(Request request) {
        return request instanceof RequestX;
    }
} 
@Component annotation on XHandler tells to Spring to instantiate an object of this type in the IOC container.
public interface HandlerManager {
    Result handle(Request request) throws NoHandlerException;
}
@Service
public class CtxHandlerManager implements HandlerManager {

    private ApplicationContext applicationContext;

    @Value("${base.package}")
    private String basePakage;

    @Autowired
    public CtxHandlerManager(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Result handle(Request request) throws NoHandlerException {
        Optional handlerOpt = findHandler(request);
        if ( !handlerOpt.isPresent() ) {
            throw new NoHandlerException();
        }
        Handler handler = handlerOpt.get();
        return handler.handle(request);
    }

    private Optional<Handler> findHandler(Request request) {
        ClassPathScanningCandidateComponentProvider provider = createComponentScanner();

        for (BeanDefinition beanDef : provider.findCandidateComponents(basePakage)) {
            try {
                Class clazz = Class.forName(beanDef.getBeanClassName());
                Handler handler = (Handler) this.applicationContext.getBean(clazz);
                //find responsible handler for the request
                if (handler.canHandle(request)) {
                    return Optional.ofNullable(handler);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return Optional.empty();
    }

    private ClassPathScanningCandidateComponentProvider createComponentScanner() {
        ClassPathScanningCandidateComponentProvider provider
                = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AssignableTypeFilter(Handler.class));
        return provider;
    }
}
CtxHandlerManager works like an Handler dispatcher.  The handle method finds the Handler and calls its handle method  which invokes the doSomething method of the Request.

In the findHandler method I use the Spring ClassPathScanningCandidateComponentProvider object with an AssignableTypeFiler to the Handler class. I call the findCandidateComponent on a basePackage (the value is set by @Value Spring annotation) and for each candidate the canHandle method check the responsability. And that's all!

In Sender class the HandlerProvider implementation (CtxHandlerManager)is injected by Spring IOC by "Autowiring":


@Service
public class Sender {

    @Autowired
    private HandlerManager handlerProvider;

    public void callX() throws NoHandlerException {
        Request requestX = new RequestX();
        Result result = handlerProvider.handle(requestX);
        ...
    }

This solution let you to add new responsibility simply creating new Request implementation and a new Handler implementation to manage it.  By applying @Component annotation on the Handler you allow Spring to autodetect the class for dependency injection when annotation-based configuration and classpath scanning is used. On application reboot, this class can be provided by the IOC Container and instantiated simply invoking the HandlerManager.

In the next post I’d like present a possible implementation of a Component Factory using the "Set of responsability" pattern in conjunction with another interesting pattern, the "Builder pattern".


Happy coding   
Mauro

No comments:

Post a Comment