C# 当(当前)只有一个类实现接口时,是否应该创建接口?

C# 当(当前)只有一个类实现接口时,是否应该创建接口?,c#,interface,yagni,C#,Interface,Yagni,如果可能有其他东西可以使用它,您是否应该始终创建一个接口,或者等到实际需要它时再进行重构以使用接口 编程到一个接口通常看起来像是合理的建议,但还有雅格尼 我想这可能要视情况而定。现在我有一个对象,它表示一个文件夹,可以包含配方或其他文件夹。与其直接使用文件夹,我是否应该担心实现类似IContainer的东西?如果将来我想有一个菜谱引用其他子菜谱(比如苹果派菜谱,它也是馅饼皮菜谱的容器)它总是取决于具体情况。如果您知道将有另一个类使用接口,那么是的,创建接口类以节省以后的时间。然而,如果你不确定(

如果可能有其他东西可以使用它,您是否应该始终创建一个接口,或者等到实际需要它时再进行重构以使用接口

编程到一个接口通常看起来像是合理的建议,但还有雅格尼


我想这可能要视情况而定。现在我有一个对象,它表示一个文件夹,可以包含配方或其他文件夹。与其直接使用文件夹,我是否应该担心实现类似IContainer的东西?如果将来我想有一个菜谱引用其他子菜谱(比如苹果派菜谱,它也是馅饼皮菜谱的容器)

它总是取决于具体情况。如果您知道将有另一个类使用接口,那么是的,创建接口类以节省以后的时间。然而,如果你不确定(大多数时候你也不确定),那就等到你需要的时候再说


现在,这并不意味着忽略接口的可能性——考虑对象的公共方法等,着眼于以后创建接口,但不要用您实际不需要的任何东西扰乱您的代码库。

我想说,这更多地取决于您将使用该类的位置,更少地关注可能实现接口的类的数量。如果您只在一两个地方使用Folder,那么我会说,在实现和重构该接口之前,请等待接口的实际需要。然而,如果文件夹将在100个不同的地方使用,那么您可以通过预先编程到一个接口来节省一些时间。

总会有一个使用它的测试,对不对(您进行单元测试,不是吗?)。这意味着总是有N+1个类使用它,其中N是在应用程序中使用您的类的类数

除了依赖项注入之外,接口的另一个用途是分离关注点,以便您的类可以实际实现多个接口


记住所有这些,但如果一开始没有实现接口,您可以在以后通过重构引入接口。

通常,如果只有一个类要实现接口,您不应该费心创建接口,即使您预期它可能会有一个类,因为在场景中实际测试该类之前可能不会出现实现问题,在这种情况下,过早创建的接口可能有太多的member,或者可能缺少一个成员

例如,.NET Framework Bas类库团队承认在包含
SyncRoot
属性时过早地设计了
ICollection
。对于后面的泛型
ICollection
,他们决定将其删除()


如果您要创建一个实现相同接口的模拟对象,那么这将被视为第二个实现,证明创建接口是正确的。但并非所有的单元测试都支持模拟式接口。

将接口视为定义语义或概念的契约。这是一种通用的方法,而不是特定于语言。在面向对象的上下文中,如果您使用的是单一继承模型,那么在定义对象模型时,最好选择接口而不是类,因为单一的超类路径非常宝贵,您希望将其保存起来,以获得比定义对象上公开的属性更“实质性”的东西,或方法

使用IContainer语义(contract)是从文件夹中创建接口的一个相当糟糕的理由;最好让您的文件夹(如果它执行任何非平凡的逻辑)在您的语言的核心框架中“实现”(可能已经存在)IContainer或ICollection接口

一如既往,更好的选择取决于具体问题。如果你的食谱也是文件夹(?!),你可能会想到一种父子关系或组合关系——一种可以(也应该)用接口表达的语义,如果你的系统中有其他元素对使用这种语义组合的东西“操作”的话

接口有一点开销(编程方面),而且,如果您发现自己只使用了一组Woof和IWoof类和接口,那么您就知道可能不需要用接口来表达您的问题——简单的类就足够了

一般来说,对于任何I,您都应该至少有两个具体的类(具有除IImpl、or之外的更有意义的名称)


希望这会有所帮助。

很多人已经提出了非常合理的建议。 我想补充的一点是,如果您希望避免对具体类的直接硬依赖,那么接口将通过提供松耦合来帮助您。 如果您正在创建一个基于插件的体系结构,那么接口无疑是一个不错的选择。此外,如果您计划并行或稍后编写单元测试,您可能会注意到,调用文件夹类的代码必须携带一个具体的实现,以便调用代码可以测试。 如果文件夹类的具体实现依次与DB或服务进行通信,那么您也需要将其带入测试中,这将很快变得非常笨拙。
只要我的2美分。

如果类足够简单,单元测试不需要模拟对象(即,它足够简单,只需要使用真实对象),该怎么办?我从来没有说过任何关于模拟对象的事,不是吗:-)?我要说的是,使用它的类的数量总是+1(test)。我同意以后可以通过简单的重构来引入接口。+1:依赖注入绝对是使用接口的驱动因素。这件事吃了我的尖括号:对于任何Ixxx。。。不结盟运动