如何为 C# 中的接口提供新行为?

How can I provide new behavior to an interface in C#?

我想修改实现特定接口的 class 实例的行为。修改由修饰符对象执行。最后,原始 class 实例仍应保留其所有其他行为。这是设置:

接口和实现 class 如下所示:

interface IFuncA
{
  double DoSomethingA();
}
interface IFuncB
{
  int DoSomethingB(string str);
}

class ImplementsAB : IFuncA, IFuncB
{
  void DoSomethingA() => 3.14;
  int DoSomethingB(string str) => str.Length;
}

有一些修饰符 class 根据以下伪代码工作。这是我无法完全弄清楚的部分。

// Unknown how to make this work.
class ModifiesFuncB
{
  int Multiplier;
  int ModifiedDoSomethingB(string str) => Multiplier * str.Length;

  ModifiesFuncB(int multiplier)
  {
    Multiplier = multiplier;
  }

  T Modify<T>(T funcB) where T : IFuncB
  {
    // This is pseudo-code.
    funcB.DoSomethingB = ModifiedDoSomethingB;
    return funcB;
  }
}

下面是一些示例代码,使用修饰符修改实现它的对象上的 IFuncB 接口的行为。

ImplementsAB myObj = new ImplementsAB();
ModifiesFuncB modifier = new ModifiesFuncB(2);

Console.WriteLine(myObj.DoSomethingA());        // Outputs 3.14
Console.WriteLine(myObj.DoSomethingB("hello")); // Outputs 5

myObj = modifier.Modify(myObj);

Console.WriteLine(myObj.DoSomethingA());        // Outputs 3.14
Console.WriteLine(myObj.DoSomethingB("hello")); // Outputs 10

是否有解决方案、软件设计模式或执行此操作的通用方法?这可能是完全错误的方法,但展示我应该做的是很大的帮助。提前致谢!

您可能正在寻找

装饰器模式 - “动态地为对象附加额外的职责。装饰器为扩展功能提供了一种灵活的子类替代方法。”( Gamma, Erich, et al. "Elements of Reusable Object-Oriented Software." Design Patterns. massachusetts: Addison-Wesley Publishing Company (1995)).

通常,您要寻找的设计模式是 Decorator。基本上,您希望创建一个新实例来包装原始实例并修改其行为,同时保留相同的接口。这有一个问题,即您想在具体的 class ImplementsAB 上调用 Modify 并期望结果仍然是那种类型 ImplementsAB。一般来说,这几乎是不可能的。让我用更正式的术语来说明。

您需要一种方法 T Modify<T>(T t) where T : IFuncB 来修改 T 的行为,但不知道 class 到底是什么。这显然是不可能的,因为您对 IFuncB 的唯一了解就是它具有 int DoSomethingB(string) 方法。你可以通过在运行时创建一个扩展 T 的 class 来实现你想要的一些反射巫术(前提是 T 不是密封的),但这比你想做的更有趣想投产

我看到了两种解决方法。

1。轻松出路

如果您可以放宽接口并期望方法是 IFuncB Modify(IFuncB funcB),则应用 classical Decorator 模式(我扩展了 IFuncB 接口以展示该模式的一般工作原理):

interface IFuncB
{
  int DoSomethingB(string str);
  void DoSomethingElse();
}

class ModifiesFuncB
{
  int Multiplier { get; }
  int ModifiedDoSomethingB(string str) => Multiplier * str.Length;

  ModifiesFuncB(int multiplier)
  {
    Multiplier = multiplier;
  }

  IFuncB Modify(IFuncB funcB) => return new ModifiedFuncB(funcB, Multiplier);

  private class ModifiedFuncB : IFuncB
  {
    private readonly int _multiplier;
    private readonly IFuncB _impl;

    public ModifiedFuncB(IFuncB impl, int multiplier) =>
      (_impl, _multiplier) = (impl, multiplier);

    public int DoSomethingB(string str) => _multiplier * str.Length;

    public void DoSomethingElse() => _impl.DoSomethingElse();
  }
}

您创建一个包装器来修改您想要的行为并将其他所有内容路由到原始实例。非常有用的模式。

2。明确实现你想要的

对于原始问题,我能找到的唯一合理解决方案是要求原始实现启用此类修改。

首先,定义一个显式启用修改的接口:

interface ICanBeModifiedB<TFrom> where TFrom : IFuncB
{
    TFrom Modify(IFuncB modifier);
}

语义是:可以通过调用 Modify 来修改此对象的 IFuncB 实现,并实现新的所需行为。

其次,在抽象中创建一个基本实现 class 这样人们就不必为每个 class:

从头开始​​实现
abstract class CanBeModifiedB<TFrom> : IFuncB, ICanBeModifiedB<TFrom> where TFrom : IFuncB
{
    private IFuncB? _modifier;

    protected abstract TFrom This { get; }

    public TFrom Modify(IFuncB impl)
    {
        _modifier = impl;
        return This;
    }

    public int DoSomethingB(string str) => 
       _modifier is null ? DoSomethingBImpl(str) : _modifier.DoSomethingB(str);

    public int DoSomethingElseB() => 
       _modifier is null ? DoSomethingElseB() : _modifier.DoSomethingElseB();
    
    protected abstract int DoSomethingBImpl(string str);
    protected abstract void DoSomethingElseBImpl();
}

如果未调用 Modify,操作将路由到原始实现。给出修饰符后,所有 IFuncB 操作都将路由到该修饰符。

最后,实现剩下的抽象成员:

class ImplementsAB : IFuncA, CanBeModifiedB<ImplementsAB>
{
  protected override ImplementsAB This => this;

  protected double DoSomethingA() => 3.14;
  protected override int DoSomethingBImpl(string str) => str.Length;
  protected override void DoSomethingElseImpl() => Console.WriteLine("Something.");
}

最后,实际展示一下:

class ModifiedB : ImplementsAB
{
    private readonly int _multiplier;
    
    public ModifiedB(int multiplier) => _multiplier = multiplier;
    
    protected override int DoSomethingBImpl(string str) => _multiplier * str.Length;
}

ImplementsAB myObj = new ImplementsAB();
ModifiesFuncB modifier = new ModifiesFuncB(2);

Console.WriteLine(myObj.DoSomethingA());        // Outputs 3.14
Console.WriteLine(myObj.DoSomethingB("hello")); // Outputs 5

myObj = modifier.Modify(myObj);

Console.WriteLine(myObj.DoSomethingA());        // Outputs 3.14
Console.WriteLine(myObj.DoSomethingB("hello")); // Outputs 10

您可以找到 full code here.

我认为您可以覆盖 ImplementsAB 中的方法。 例如

interface IFuncA
{
    double DoSomethingA();
}


interface IFuncB
{
    int DoSomethingB(string str);
}


class ImplementsAB : IFuncA, IFuncB
{
    public virtual int DoSomethingB(string str)
    {
        return 222222;
    }

    public double DoSomethingA()
    {
        return 333333;
    }
}


class ModifiesFuncB : ImplementsAB
{
    // Do whatever you want here and override the method when you want to use it with different behavior
    public override int DoSomethingB(string str)
    {
        return 999;
    }

}

你可以看到模式抽象工厂。您也可以为 class 设置不同的行为。 我在 GitHub 上有一个例子:https://github.com/renanslucena88/DesignPatterns

希望对您有所帮助。