C# 为每个类提取接口是最佳实践吗?
我见过这样的代码:每个类都有一个它实现的接口 有时它们都没有通用的接口 它们就在那里,它们被用来代替具体的物体 它们不为两个类提供通用接口,并且特定于类所解决问题的领域 有什么理由这样做吗?如果是原则的一部分。基本上,代码取决于接口,而不是实现 这允许您轻松地交换实现,而不会影响调用类。它允许更松散的耦合,使系统的维护更容易C# 为每个类提取接口是最佳实践吗?,c#,interface,software-design,C#,Interface,Software Design,我见过这样的代码:每个类都有一个它实现的接口 有时它们都没有通用的接口 它们就在那里,它们被用来代替具体的物体 它们不为两个类提供通用接口,并且特定于类所解决问题的领域 有什么理由这样做吗?如果是原则的一部分。基本上,代码取决于接口,而不是实现 这允许您轻松地交换实现,而不会影响调用类。它允许更松散的耦合,使系统的维护更容易 随着系统的发展和变得越来越复杂,这个原则越来越有意义 接口定义了一种行为。如果实现一个或多个接口,则对象的行为与所描述的一个或多个接口类似。这允许类之间的松散耦合。当您必须
随着系统的发展和变得越来越复杂,这个原则越来越有意义 接口定义了一种行为。如果实现一个或多个接口,则对象的行为与所描述的一个或多个接口类似。这允许类之间的松散耦合。当您必须用另一个实现替换一个实现时,它非常有用。类之间的通信应始终使用接口完成,除非类之间确实紧密地绑定在一起。如果您希望确保将来能够注入其他实现,则可能会有。对于某些(也许是大多数)情况,这是一种过度的杀伤力,但对于大多数习惯来说也是如此——如果你习惯了,你就不会有太多时间去做。而且,由于您永远无法确定将来要替换什么,因此在每个类上提取接口是有意义的
对于一个问题,从来都不是只有一个解决方案。因此,同一接口可能总是有多个实现。这可能看起来很愚蠢,但这样做的潜在好处是,如果在某个时候你意识到有更好的方法来实现某个功能,你可以编写一个实现同一接口的新类,并更改一行,使所有代码都使用该类:分配接口变量的行 这样做(编写一个实现相同接口的新类)也意味着您可以始终在新旧实现之间来回切换以进行比较 结果可能是,您永远不会利用这种便利性,最终产品实际上只使用为每个接口编写的原始类。如果是这样,那太好了!但是编写这些接口并没有花费太多时间,如果您需要它们,它们会为您节省大量时间。在重新审视这个答案后,我决定对其进行一些修改 不,为每个类提取接口不是最佳实践。这实际上可能适得其反。但是,接口之所以有用,有几个原因:
- 测试支持(模拟、存根)
- 实现抽象(进一步扩展到IoC/DI)
- C#中的协方差和逆变支持等辅助功能
我将把我的旧答案留给上下文 接口定义公共契约。实现接口的人员必须实现此合同。消费者只看到公共合同。这意味着实现细节已从使用者抽象出来 目前,这种方法的一个直接用途是单元测试。接口很容易模仿,存根,伪造,随便你说 另一个直接的用途是依赖注入。为给定接口注册的具体类型提供给使用接口的类型。类型并不特别关心实现,因此它可以抽象地请求接口。这允许您在不影响大量代码的情况下更改实现(只要契约保持不变,影响范围就非常小)
对于非常小的项目,我倾向于不费心,对于中等项目,我倾向于在重要的核心项目上费心,对于大型项目,几乎每个类都有一个接口。这几乎总是为了支持测试,但在某些情况下,注入行为或行为抽象可以减少代码重复。我不认为这对每个类都是合理的
问题在于您希望从哪种类型的组件中获得多少重用。当然,您必须计划更多的重用(无需稍后进行重大重构),而不是当前实际使用的重用,但是为程序中的每个类提取抽象接口将意味着您的类比需要的少 接口很好,因为您可以在(单元)测试时模拟类 我至少为所有涉及外部资源(如数据库、文件系统、Web服务)的类创建接口,然后编写一个模拟或使用模拟框架来模拟行为。没有实践
class Coordinate
{
public Coordinate( int x, int y);
public int X { get; }
public int y { get; }
}
class RoutePlanner
{
// Return a new list of coordinates ordered to be the shortest route that
// can be taken through all of the passed in coordinates.
public List<Coordinate> GetShortestRoute( List<Coordinate> waypoints );
}
class RobotTank
{
public RobotTank( IRoutePlanner );
public void DriveRoute( List<Coordinate> points );
}