如果可能有其他东西可以使用它,您应该始终创建一个接口,还是等到实际需要它然后重构以使用接口?
对接口进行编程通常似乎是合理的建议,但是还有 YAGNI ......
我想也许这取决于情况。现在我有一个对象代表一个可以包含食谱或其他文件夹的文件夹。我应该担心实现 IContainer 之类的东西,而不是直接使用 Folder 吗?以防将来我想要一个引用其他子食谱的食谱(比如一个苹果派食谱,它也是一个馅饼皮食谱的容器)
这总是取决于情况。如果您知道将有另一个类使用该接口,那么是的,创建接口类以节省时间。但是,如果您不确定(并且大多数情况下您不确定),那么请等到您需要它。
现在这并不意味着忽略接口的可能性 - 考虑对象的公共方法等,着眼于稍后制作接口,但不要用任何你实际上不需要的东西弄乱你的代码库。
总会有一个使用它的测试,对吧(你做单元测试,不是吗?)。这意味着总是有 N + 1 个类使用它,其中 N 是在应用程序中使用您的类的类的数量。
除了依赖注入之外,接口的另一个目的是关注点分离,以便您的类实际上可以实现多个接口。
请记住所有这些,但如果一开始没有实现,您总是可以稍后通过重构引入接口。
一般来说,如果只有一个类要实现它,您不应该为创建接口而烦恼,即使您预计它可能有一个类,因为可能会出现实现问题,直到该类在一个实际测试中才会出现场景,在这种情况下,过早创建的接口可能有太多的成员或可能缺少成员。
例如,.NET Framework Bas 类库团队承认ICollection
在包含SyncRoot
属性时过早地进行了设计。对于后来的泛型ICollection<T>
,他们决定将其删除(http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx)。
如果您要创建一个实现相同接口的模拟对象,那么这将被视为证明创建该接口的第二个实现。不过,并非所有单元测试都需要模拟风格的界面。
我想说这更多地取决于您将要使用该类的地方,而不是可能实现该接口的类的数量。如果您只在一个或两个地方使用 Folder,那么我会说等到真正需要该接口,然后再实现它并进行重构。但是,如果文件夹要在 100 个不同的地方使用,那么您可以通过预先编程到界面来节省一些时间。
将接口视为定义语义或概念的合同。这是一种通用方法,并不是特定于语言的。在 OO 的上下文中,如果您使用的是单一继承模型,那么在定义对象模型时优先选择接口而不是类是一个很好的案例,因为单一的超类路径非常宝贵,您希望将其保存为比定义在对象或方法上公开的属性更“实质性”的东西。
拥有 IContainer 语义(合同)是从文件夹中创建接口的一个相当糟糕的理由;最好让您的文件夹(如果它正在执行任何重要的逻辑)在您的语言的核心框架中“实现”(可能已经存在的)IContainer 或 ICollection 接口。
与往常一样,更好的选择完全取决于具体问题。如果您的食谱也是文件夹(?!),您可能正在考虑父子关系或组合关系 - 如果您的系统中有其他元素,可以(并且应该)使用接口表达的语义对使用这种语义组成的事物进行“操作”。
接口有一点开销(编程方面),而且,如果你发现自己只需要一组 Woof 和 IWoof 类和接口,那么你就会知道你可能不需要表达你在接口方面的问题——简单的类就足够了。
通常,对于任何 I,您都应该至少有几个具体的类(除了 IImpl 或 之外,还有更有意义的名称)。
希望有帮助。
很多人已经提出了非常合理的建议。我想补充的一件事是,如果您希望避免对具体类的直接硬依赖,那么接口将通过提供松散耦合来提供帮助。如果您正在创建基于插件的架构,那么接口绝对是您的最佳选择。此外,如果您计划并排或稍后编写单元测试,您可能会注意到调用文件夹类的代码必须携带一个具体的实现,以便调用代码可测试. 如果您的文件夹类的具体实现又与数据库或服务通信,那么您也需要将其转移到您的测试中,这将很快变得笨拙。只是我的2美分。