为什么我们的项目需要接口层/抽象类?

我们通常在项目中使用抽象函数/接口。 为什么真的需要它? 为什么我们不能只去商业逻辑层,数据访问层和表示层

表示层中的function:

abc(); 

业务逻辑层中的function:

  public void abc() { //Preparing the list } 

数据访问层中的function:

 public abstract void abc(); 

数据访问SQLServer层中的function:

  public override void abc() { //Connection with database } 

问题是:为什么需要数据访问层?

理解这一点的最简单方法是imo,它是对DataLayer一种抽象。

您已设置函数以从xml文件中检索数据。 但是有一天你的产品会缩小,而xml就像数据存储一样。 所以你传递给一些嵌入式数据库: sqlite 。 但有一天,您需要在某些企业环境中重用您的库。 因此,现在您需要开发对sqlserveroraclewebservice访问….在所有这些更改中,您不仅需要更改实际访问数据的代码,还需要更改实际使用它的代码。 那些已经使用多年的客户端第一次xml数据访问并且满意的代码呢? 反向兼容性怎么样?

如果没有直接解决大部分问题的抽象,但绝对可以使你的应用程序可扩展,并且更能抵抗变化,在我们的世界中,有时候太频繁发生。

通常,如果在代码中使用接口,那么您将以dependency injection的forms获得代码可操作性。

这将帮助您在某些情况下替换部分实现,例如在unit testing期间提供Mock对象。

为什么接口:你曾经在c#中使用过:using(Form f = new Form()){}

在这里,您将看到只能使用实现IDisposable接口的那些类。

彼此不了解的两件事只能使用Interfaces相互交互。 界面保证“某些”function肯定是通过这种类型实现的。

为什么图层:

这样你就可以拥有单独的dll,它们可以让你在不同的应用程序中重用。

基本上所有都是代码重用和性能提升。

我想你在谈论Facade层。

它是一个可选层 ,它将简化业务层的function。 让我们假设您有一个ProductManager和CategoryManager,并且您想要执行一个涉及使用两者的特定操作(例如,在所有类别中获取前5个产品),然后您可以使用使用ProductManager和CategoryManager的外观层。

它的灵感来自Facade Pattern 。

抽象有助于创建function,无论是通过基类,接口还是组合,如果使用得当,都会对维护,可读性和代码的可重用性产生奇迹。

关于问题中发布的代码,标记为“数据访问层”的代码充当业务层要使用的通用抽象。 通过这样做,DAL的特定实现(例如样本中“数据访问SQLServer层”下的内容)与业务层分离。 现在,您可以实现访问不同数据库的DAL,或者可以自动提供数据以进行测试等。

存储库模式是在DAL中工作的一个很好的例子(示例是简化的):

 public interface IProductRepository { Product Get(int id); ... } public class SqlProductRepository : IProductRepository { public Product Get(int id) { ... } ... } public class MockProductRepository : IProductRepository { private IDictionary _products = new Dictionary() { { 1, new Product() { Name = "MyItem" } } }; public Product Get(int id) { return _products[id]; } ... } public class AwesomeBusinessLogic { private IProductRepository _repository; public AwesomeBusinessLogic(IProductRepository repository) { _repository = repository; } public Product GetOneProduct() { return _repository.GetProduct(1); } } 

尽管此示例使用接口,但同样适用于基类的使用。 美妙的是,现在我可以将SqlProductRepositoryMockProductRepositoryAwesomeBusinessLogic而不必更改任何有关AwesomeBusinessLogic 。 如果出现另一个案例,那么所需要的只是IProductRepository一个新实现,而AwesomeBusinessLogic仍然可以不加改变地处理它,因为它只通过接口访问存储库。

所有以前的答案都可以解释抽象层的需求,但我仍然想补充一些我的想法。

让我们说在我们的项目中,我们在每一层中只有一个服务实现。 例如,我有联系DAL和联系BLL服务,我们可以做这样的事情

 namespace Stackoverflow { public class ContactDbService { public Contact GetContactByID(Guid contactID) { //Fetch a contact from DB } } } 

联系BLL服务:

 namespace Stackoverflow { public class ContactBLLService { private ContactDbService _dbService; public ContactBLLService() { _dbService = new ContactDbService(); } public bool CheckValidContact(Guid contactID) { var contact = _dbService.GetContactByID(contactID); return contact.Age > 50; } } } 

没有定义接口/抽象类。

如果我们这样做,会有一些明显的缺点。

  1. 代码沟通:想象一下,如果您的项目涉及,您的服务可能有许多不同的方法,维护者(除了您)如何知道您的服务有什么作用? 他是否必须阅读您的整个服务才能修复像InvalidCastOperation这样的小错误? 通过查看界面,人们将立即了解服务的function(至少)。
  2. unit testing

    您可以使用假/模拟服务测试您的逻辑,以提前检测错误,并防止以后发生回归错误。

  3. 更容易更改:

    通过仅通过其他类中的接口/抽象类进行引用,您可以在不需要太多工作的情况下轻松地替换这些接口实现。

抽象类或接口实际上不是一个单独的层 – 它应该是业务逻辑层的一部分,它定义了实际数据访问层(例如SQL数据存储库)需要实现的接口,以提供数据访问服务您的业​​务层。

如果没有此接口,您的业务层将直接依赖于SQL层,而接口将删除此依赖关系:您将抽象类或接口放入业务逻辑层。 然后SQL层(例如,单独的程序集)实现抽象类/接口。 这样,SQL层依赖于业务层,而不是相反。

结果是一个灵活的应用程序,具有可以与多个数据存储库一起使用的独立业务层 – 它所需要的只是一个实现业务层定义的接口的层。 而且它实际上并不只是关于数据存储库 – 您的业务层不应该依赖于上下文(asp.net与控制台应用程序与服务等),它不应该依赖于用户界面类,模块接口与您的业务应用程序等

抽象使您可以快速进行重构。 考虑使用SQL服务器,您决定使用其他一些提供程序; 如果您没有数据访问层,那么您需要执行一个巨大的重构,因为您直接调用数据访问方法。 但是,如果您有数据访问层,则只需编写一个新的数据访问层,inheritance自抽象数据访问层,并且不会更改业务层中的任何内容。