I currently have a command handling interface that is implemented by a few different classes for different command types. I'm using the Decorator Pattern in conjunction with an IoC container (Unity in my case) to add cross cutting concerns to those handlers, so I created a few classes like:
- ValidatorCommandHandlerDecorator
- LoggingCommandHandlerDecorator
- AsyncCommandHandlerDecorator
This is all working as expected and is actually very nice. The potential problem here is that the code contracts for the interface is checked for every decorator implementation. I would like to potentially avoid that by only validating the contract once (preferably on the outermost decorator).
Is there something available out of the box to accomplish that? If not, what would be your suggestion to overcome this issue?
The generic interface and the contract class are like this:
[ContractClass(typeof(CommandHandlerContracts<>))]
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
[ContractClassFor(typeof(ICommandHandler<>))]
internal abstract CommandHandlerContracts<TCommand>
: ICommandHandler<TCommand>
{
public void Handle(TCommand command)
{
Contract.Requires<ArgumentNullException>(
command != null);
}
}
And the ValidatorCommandHandler (as an example of how I'm implementing them) looks like this:
public sealed class ValidatorCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> m_decoratedHandler;
private ICommandValidator<TCommand> m_commandValidator;
public ValidatorCommandHandlerDecorator(
ICommandHandler<TCommand> decoratedHandler,
ICommandValidator<TCommand> commandValidator)
{
m_decoratedHandler = decoratedHandler;
m_commandValidator = commandValidator;
}
public void Handle(TCommand command)
{
m_commandValidator.Validate(command);
m_decoratedHandler.Handle(command);
}
}
Even if I created another interface to use just for the decorators, it would have to inherit the original interface and the contracts would still be checked, so I'm not sure how to go about this.
This is .NET 4.0 / VS2012 and I'm using the latest version of Code Contracts, if this helps any.