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