2

在 C#8 中,微软为接口方法引入了默认实现。这仍然是一个相当新的功能,似乎有很多相关的博主都在写这个。

我想知道的是,默认实现是否有可能成为依赖倒置和 DI 的有用工具,或者它是否会促进不良的编程风格?它是否违反了任何众所周知的原则,例如 SOLID?

4

1 回答 1

6

默认接口实现有两个主要的设计目标。更重要的是可以追溯到关于设计界面的指南。特别是,一旦你发布了一个界面,它就应该是一成不变的,永远不会改变。问题是,这也是一条一直被忽视的规则。

第一个也是主要的实用程序是默认接口实现允许您将新成员引入接口,而不会破坏与该(公共)接口消费者的源代码或二进制兼容性。这仍然限制了您在更改公共界面时可以进行的更改类型,但也使客户更容易使用新界面 - 升级是免费的,他们可以立即开始使用新功能。

第二个设计目标是用特性扩展类的方法——这在游戏开发中早已被使用。基本思想是,您可以通过让类实现接口来向类添加新的明确定义的行为,同时还保留修改类本身行为的能力。这本质上是一种相对较弱的元编程形式。

当然,仅仅因为这些是设计目标并不意味着它们是您应该使用默认实现的唯一方式。但是如果你概括一下,你会得到这两个基本用途:

  • 在不破坏兼容性的情况下扩展接口并且不必对接口进行版本化。
  • 扩展类,而不必创建从类继承中获得的严格的树层次结构。

事实上,你甚至可以说这比类继承更简单、更清晰、更强大。在某种程度上,这是从扩展方法开始的方法的延续——本质上,默认接口方法实现是一个扩展方法,也是虚拟的。默认实现只能使用公共接口,但实现类也可以使用自己的隐藏状态。它为 C# 提供了一种有限形式的多重继承,而无需处理如何将两个“父级”的状态连接在一起(因为接口没有任何状态)。

最后,如果您担心像 SOLID 这样的原则,让我们试一试:

  • SRP - 没有真正的变化,在一个地方非破坏性地添加新逻辑的一些新选项。我说这对 SRP 来说是一个小小的胜利。
  • OCP - 您可以获得扩展类的强大新方法,而无需修改类本身,只要该类实现了一个新特性有意义的接口。但是您不能以这种方式更改现有类的行为,因此它仍然关闭以供修改。在这里获胜非常有用。
  • LSP - 没有真正受到影响。仅通过实现接口(可以根据需要覆盖该行为的选项)允许您向类添加新的可替代行为,取得了一些小胜利。
  • ISP - 这可以双向进行。如果您有合理的默认实现,默认实现可能会使拥有许多小接口变得更容易。但他们也可以鼓励您继续修改现有界面而不是添加新界面。
  • DIP - 基本不受影响。如果新的抽象是对现有抽象的合理扩展,或者可以在不依赖状态的情况下实现默认行为,则可以更轻松地添加新抽象。您也可以尝试将默认行为用作合同,但在 IMO 中,它仍然比抽象方法(您还可以控制状态)中的诱惑少。
于 2019-11-26T08:30:07.587 回答