I am always struggling with decoration + interfaces. Say I have the following \'behavior\' interfaces :
interface IFlyable { void Fly();}
interface ISwimmable {
You will need to create separate decorators for each interface. An alternative is to use a generic interface for your services and a generic decorator. For example:
public interface ICommandService<TCommand>
{
Task Execute(TCommand command);
}
public class LoggingCommandService<TCommand> : ICommandService<TCommand>
{
public LoggingCommandService(ICommandService<TCommand> command, ILogger logger)
{
...
}
public async Task Execute(TCommand command)
{
// log
await this.command.Execute(command);
// log
}
}
I think you are steering right into the service locator pattern - which is a severe anti-pattern. You have a service locator, if you depend on an interface that acts like a wishing well: you can ask it for anything. I think that this is exactly where your GetAs
is getting you to.
Service locator is considered an anti-pattern because it hides the dependencies that a class has. Instead, you only see the service locator as single dependency but you don't immediately see what dependencies are going to be called.
If you ask for an implementation, I would recommend to use a dependency injection framework. There are plenty of them on the market like MEF, Ninject, Unity, Windsor, DryIoC, SimpleInject, LightInjector, Grace, Stashbox, ... just to name a few that come to my mind.
The point of a decorator is something completely different. A decorator is used if you do NOT just forward the interface calls, but add some extra logic (such as a retry behaviour) to it. In that case, you would however still limit yourself to the methods of the original interface.
The Decorator Pattern is not intended for adding new methods to the decorated object. This is what you are trying to do, and it's impossible to do elegantly in a statically-typed language.
What Decorator is useful for is where the interface to the decorators and the decorated component is the same, and the decorator adds a bit of extra functionality to the method either before or after passing the request along the decorator chain.