问题描述
我一直在努力装饰+接口.假设我有以下行为"界面:
I am always struggling with decoration + interfaces. Say I have the following 'behavior' interfaces :
interface IFlyable { void Fly();}
interface ISwimmable { void Swim();}
主界面
interface IMainComponent { void DoSomethingA(); void DoSomethingB();}
主界面上的装饰器
public class Decorator : IMainComponent
{
private readonly IMainComponent decorated;
[..]
public virtual void DoSomethingA()
{
decorated.DoSomethingA();
}
public virtual void DoSomethingB()
{
decorated.DoSomethingB();
}
}
我的问题是如何将装饰对象实现的所有接口转发给装饰器.一种解决方案是使装饰器实现接口:
My issue is how to forward all the interfaces implemented by the decorated object to the decorator. A solution is to make the decorator implementation the interfaces :
public class Decorator : IMainComponent, IFlyable, ISwimmable
{
[..]
public virtual void Fly()
{
((IFlyable)decorated).Fly();
}
public virtual void Swim()
{
((ISwimmable)decorated).Swim();
}
但是我不喜欢它,因为:
But I don't like it because :
- 情况并非如此(运行时的Cast异常),看起来装饰器"实现了一个接口
- 这是不可扩展的,我需要添加每个新接口(不要忘记此添加)
另一种解决方案是添加手动投射"以传播装饰树:
An other solution is to add "a manual cast" that propagates throw the decoration tree :
public class Decorator : IMainComponent
{
public T GetAs<T>()
where T : class
{
//1. Am I a T ?
if (this is T)
{
return (T)this;
}
//2. Maybe am I a Decorator and thus I can try to resolve to be a T
if (decorated is Decorator)
{
return ((Decorator)decorated).GetAs<T>();
}
//3. Last chance
return this.decorated as T;
}
但是问题是:
- 在调用GetAs()之后,调用者可以操纵包装的对象.
- 如果在调用GetAs之后使用IMainComponent中的方法,这可能导致混乱/不必要的行为(类似((IMainComponent)GetAs()).DoSomethingB(); ==>这可能会调用包装对象的实现),而不是完整的装饰.
- 需要调用GetAs()方法,并且退出带有强制转换/常规"As"的代码将无效.
您如何解决/解决此问题?是否有解决此问题的模式?
How to you approch/resolve this issue ? Is there a pattern addressing this issue ?
PD:我的问题是最终的C#实现,但是解决方案可能更广泛.
PD : my question is for a final C# implementation but maybe the solution is more broad.
推荐答案
您将需要为每个接口创建单独的装饰器.一种替代方法是为您的服务和通用装饰器使用通用接口.例如:
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
}
}
这篇关于装饰有几个界面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!