我一直在努力装饰+接口(interface)。说我有以下“行为”界面:

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();
        }
    }

我的问题是如何将装饰对象实现的所有接口(interface)转发给装饰器。一个解决方案是使装饰器实现接口(interface):
    public class Decorator : IMainComponent, IFlyable, ISwimmable
    {
        [..]

        public virtual void Fly()
        {
            ((IFlyable)decorated).Fly();
        }

        public virtual void Swim()
        {
            ((ISwimmable)decorated).Swim();
        }

但我不喜欢它,因为:
  • 并非如此(运行时的Cast异常),它看起来像是“装饰器”实现了一个接口(interface)
  • 这是不可扩展的,我需要添加每个新接口(interface)(不要忘记此添加)

  • 另一种解决方案是添加“手动转换”以传播装饰树:
        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”的代码将不起作用。

  • 您如何解决/解决此问题?有解决此问题的模式吗?

    PD:我的问题是最终的C#实现,但是解决方案可能更广泛。

    最佳答案

    您将需要为每个接口(interface)创建单独的装饰器。一种替代方法是为您的服务和通用装饰器使用通用接口(interface)。例如:

    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
      }
    }
    

    关于c# - 装饰有几个界面,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55166176/

    10-11 07:28
    查看更多