为什么我们需要在 C# 中 UI、业务和数据访问之间的接口

Pra*_*sob 1 c# 3-tier n-tier-architecture

我在很多地方看到c#程序员在使用3-tire架构时,往往会在每一层之间使用接口。例如,如果解决方案是这样的

SampleUI
Sample.Business.Interface
Sample.Business
Sample.DataAccess.Interface
Sample.DataAccess
Run Code Online (Sandbox Code Playgroud)

这里UI通过接口调用业务层,业务调用数据访问的方式相同。如果这种方法是为了减少层之间的依赖关系,它已经与类库一起使用,无需额外使用接口。代码示例如下,

样品.业务

public class SampleBusiness{
   ISampleDataAccess dataAccess = Factory.GetInstance<SampleDataAccess>();
   dataAccess.GetSampledata();
}
Run Code Online (Sandbox Code Playgroud)

示例.DataAccess.Interface

public interface IsampleDataAccess{
   string GetSampleData();
}
Run Code Online (Sandbox Code Playgroud)

示例.数据访问

public class SampleDataAccess:ISampleDataAccess{
  public string GetSampleData(){
     returns data;// data from database
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 这种介于两者之间的推理有什么好的工作吗?
  2. 如果我使用 newSampleDataAccess().SampleData() 并删除完整的接口类库会怎样?

The*_*aot 6

代码契约

在设计过程中使用接口有一个显着的优势:它是一种契约。

接口是契约的规范,在这个意义上:

  • 如果我使用(使用)接口,我就会限制自己使用接口公开的内容。好吧,除非我想玩脏(反射等)。

  • 如果我实现了接口,我就会限制自己提供接口公开的内容。

以这种方式做事的优点是可以简化开发团队在各层之间的工作划分。它允许一层的开发人员提供一个咳咳接口咳咳,下一层可以用它来与之通信......甚至在实现这样的接口之前。

一旦他们就接口达成一致。至少在最小可行接口上。他们可以开始并行开发这些层,因为知道另一个团队将遵守他们的合同部分。


嘲讽

以这种方式使用接口的一个副作用是它允许模拟组件的实现。这简化了单元测试的创建。通过这种方式,您可以单独测试层的实现。因此,您可以轻松区分何时由于层存在缺陷而失败,以及何时由于下层存在缺陷而导致层失败。

对于由一个人开发的项目,或者由一个团队开发的项目,他们在划分工作时不太费心,mock的能力可能是他们实现接口的主要动机。

例如,考虑一下,如果您想测试您的表示层是否可以正确处理分页……但是您需要请求数据来填充这些页面。情况可能是这样:

  • 下面的层还没有准备好。
  • 数据库尚无数据可提供。
  • 它失败了,他们不知道分页代码是否正确,缺陷来自代码更深的一点
  • 等等…

无论哪种方式,解决方案都是嘲笑。此外,如果您有要模拟的接口,则模拟会更容易。


改变实施

如果出于某种原因,某些开发人员决定要更改其层的实现,则他们可以信任接口强加的契约。这样,他们可以交换实现而无需更改其他层的代码。

什么原因?

  • 也许他们想测试一项新技术。在这种情况下,他们可能会创建一个替代实现作为实验。此外,他们希望两个版本都能工作,以便他们可以测试哪一个更有效。

    附录:不仅用于测试两个版本,还可以轻松回滚到主版本。当然,他们可能会通过源代码版本控制来实现这一点。因此,我不会考虑将回滚作为使用接口的动机。然而,对于不使用版本控制的任何人来说,这可能是一个优势。对于任何不使用它的人......开始使用它!

  • 或者他们可能需要将代码移植到不同的平台或不同的数据库引擎。在这种情况下,他们可能也不想丢弃旧代码……例如,如果他们有运行 Windows 和 SQL Server 的客户端以及其他运行 Linux 和 Oracle 的客户端,那么维护这两个版本是有意义的。

当然,无论哪种情况,您都希望能够通过尽可能少的工作来实现这些更改。因此,您不想更改上面的层以针对不同的实现。相反,您可能会有某种形式的工厂控制容器反转,您可以将其配置为使用您想要的实现进行依赖注入


减轻变更传播

当然,他们可能会决定更改实际接口。如果在某个层上工作的开发人员需要在界面上添加一些额外的东西,他们可以将它添加到界面中(考虑到团队为批准这些更改而设置的任何方法),而不会弄乱其他团队正在工作的类的代码在。在源代码版本控制中,这将缓解边距更改。


最后,使用层架构的目的是分离关注点。这意味着更改原因的分离......如果您需要更改数据库,您的更改不应传播到专用于向用户呈现信息的代码中。当然,团队可以通过具体的类来实现这一点。然而,界面提供了一个良好的、明显的、定义明确的、支持语言的障碍来阻止变化的传播。特别是如果团队对责任有很好的规则(不,我不是说代码问题,我的意思是开发人员负责做什么)。