委托(Lambda表达式)Vs接口和抽象类

GET*_*Tah 18 c# api design-patterns

我一直在寻找这个设计问题的简洁答案但没有成功.我既没有在".NET Framework设计指南"中也没有在"C#编程指南"中找到帮助.我基本上必须将模式公开为API,以便用户可以将他们的算法定义并集成到我的框架中,如下所示:

1)

// This what I provide
public abstract class AbstractDoSomething{
   public abstract SomeThing DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

用户需要实现这个抽象类,他们必须实现该DoSomething方法(我可以在我的框架内调用并使用它)

2)

我发现这也可以通过使用代表来实现:

public sealed class DoSomething{
   public String Id;
   Func<SomeThing> DoSomething;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,用户只能以DoSomething这种方式使用类:

DoSomething do = new DoSomething()
{
  Id="ThisIsMyID",
  DoSomething = (() => new Something())
}
Run Code Online (Sandbox Code Playgroud)

这两个选项中的哪一个最适合作为API公开的简单,可用和最重要的理解

编辑

1的情况下:注册以这种方式完成(假设MyDoSomething扩展AbstractDoSomething:

MyFramework.AddDoSomething("DoSomethingIdentifier", new MyDoSomething());
Run Code Online (Sandbox Code Playgroud)

如果是2:注册完成如下:

MyFramework.AddDoSomething(new DoSomething());
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 15

这两个选项中的哪一个最适合作为API公开的简单,可用和最重要的理解?

第一个是OOP方面更"传统",对许多开发人员来说可能更容易理解.它还可以在允许用户管理对象的生命周期方面具有优势(即:您可以让类IDisposable在关闭时实现和处理实例等),以及在将来的版本中以一种方式轻松扩展不会破坏向后兼容性,因为将虚拟成员添加到基类不会破坏API.最后,如果你想使用像MEF这样的东西自动组合它可以更简单,这可以从用户的角度简化/删除"注册"过程(因为他们可以创建子类,并将其放入文件夹,让它自动发现/使用).

第二种是更具功能性的方法,并且在许多方面更简单.这允许用户使用现有代码的更改实现您的API,因为他们只需要在带有闭包的lambda中包装必要的调用,而不是创建新类型.

话虽这么说,如果你打算采用委托的方法,我甚至不会让用户创建一个类 - 只需使用如下方法:

MyFramework.AddOperation("ThisIsMyID", () => DoFoo());
Run Code Online (Sandbox Code Playgroud)

在我看来,这使得它更加清晰,您可以直接向系统添加操作.它还完全消除了对公共API(DoSomething)中另一种类型的需求,这再次简化了API.

  • @GETah但有一件事需要注意 - 如果你使用抽象类,后来想要为它添加另一个操作,你必须使它成为虚拟的,而不是抽象的,否则你将破坏兼容性(这消除了使用课程的优势). (2认同)
  • 您还需要考虑与现有API的一致性.一致性非常重要.在API中引入新概念并不能解决实际问题并不是一种好的做法. (2认同)

Ort*_*iga 7

如果符合以下情况,我会使用抽象类/接口:

  • DoSomething是必需的
  • DoSomething通常会变得非常大(所以DoSomething的实现可以分成几个私有/受保护的方法)

如果符合以下条件我会和

  • DoSomething可以被视为一个事件(OnDoingSomething)
  • DoSomething是可选的(因此您将其默认为无操作委托)