为啥我们的项目需要接口层/抽象类? [关闭]

Posted

技术标签:

【中文标题】为啥我们的项目需要接口层/抽象类? [关闭]【英文标题】:Why Interface Layer/Abstract classes required in our project? [closed]为什么我们的项目需要接口层/抽象类? [关闭] 【发布时间】:2012-03-30 21:59:31 【问题描述】:

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

表示层中的功能:

abc();

业务逻辑层的功能:

 public void abc()
    
      //Preparing the list
    

数据访问层的功能:

public abstract void abc();

数据访问 SQLServer 层中的功能:

 public override void abc()
    
       //Connection with database
    

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

【问题讨论】:

【参考方案1】:

imo 理解这一点的最简单方法是对DataLayer 进行抽象。

您已经设置了一个函数来从xml 文件中检索数据。但是有一天你的产品会横向扩展,xml 还不够像数据存储。所以你传递给一些嵌入式数据库:sqlite。但是有一天,您需要在某些企业环境中重用您的库。因此,现在您需要开发对sqlserveroraclewebservice...的访问权限。在所有这些更改中,您需要更改不仅实际访问数据的代码,而且实际上也使用它的代码。多年来,您在客户端上的第一个 xml 数据访问已经使用了多年并且对此感到满意的代码呢?后向兼容性如何?

如果不直接解决大部分此类问题,那么抽象肯定可以使您的应用程序具有可扩展性,并且更能抵抗变化,在我们的世界中,这种变化有时发生得太频繁了。

【讨论】:

我的问题得到了改进。对吧?需要投票才能重新打开它.... 我之前没有投票赞成关闭它。 当您说“向后兼容性如何?”时无法理解。能不能说的更精确一点? 或者你能举个例子吗? 如果您的应用程序在所有架构变化中都有一个抽象层来访问数据,对于使用本地 xml 文件的客户端在更新到最新版本后不会有太大变化您使用 Azure 的应用程序。您有一个使用相同集合的单一抽象函数:在访问xml 之前和访问cloud 之后。如果您的程序中有 5 年前由第三方开发人员编写的代码,则无需触摸该代码即可继续完美运行,无需任何关于真实数据源的特殊知识。【参考方案2】:

通常,如果您在代码中使用接口,那么您将以依赖注入的形式获得代码可操作性。

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

【讨论】:

你也可以在这里加入聊天chat.***.com/rooms/8875/…【参考方案3】:

为什么接口: 你有没有在 c# 中使用过 using : 使用 (Form f = new Form())

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

两个互不认识的事物只能通过接口进行交互。 接口保证“某些”功能肯定是由这种类型实现的。

为什么要分层:

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

基本上都是为了代码重用和性能提升。

【讨论】:

接口保证“某些”功能肯定已经被这种类型实现了。所以我需要在完整的项目中追踪所有接口的实现!!! 不是这样。我们不会为自己编写接口。实现接口的代码/类告诉别人“嘿,看”,“我就是这种类型,你可以使用我”。例如您的 PC USB 插座。想象一下,您创办了一家价值 10 亿美元的公司,提供 USB - 超快、便宜等。但唯一的问题是,您连接到 PC 的 USB 区域可以说是 Hexagonal。您还创建了自己的计算机,该计算机具有用于此 USB 的六角端口。现在告诉我,你的 USB 可以被全世界使用吗?当然不是!您的 USB 提供的 INTERFACE 与其他 PC 不匹配。 但是USB可以被你的电脑使用,因为它有六角插座。只需将 USB=Data 访问层和您的计算机视为 UI 层。如果您不希望其他项目使用您的数据访问层,那么“您不需要任何接口”。这个例子代表了你为什么需要接口的一小部分,还有更多……谷歌它们,你会发现更多。您的 USB 将只在您身边,无论它多么快速和便宜,它对其他人没有用,只有您可以使用它。 我的每个项目都是一个单独的项目。松散耦合。 如果你愿意将你的层分享给外界,那么你可能需要有接口。 Abstarct 类有不同的用途(有时使用接口的实现可以等同于抽象类,但请注意......它们是不同的东西。例如 1 / 1 和 1 * 1 都等于 1,这并不意味着除法和乘法是一样的。【参考方案4】:

我认为您在谈论 Facade 层。

这是一个可选层,它将简化业务层的功能。让我们想象一下,您有一个 ProductManager 和 CategoryManager,并且您想要执行一个涉及使用两者的特定操作(例如,让我获得所有类别中的前 5 个产品),那么您可以使用一个使用 ProductManager 和 CategoryManager 的外观层。

灵感来自Facade Pattern。

【讨论】:

【参考方案5】:

抽象有助于创建功能,无论是通过基类、接口还是组合,如果使用得当,可以为代码的维护、可读性和可重用性带来奇迹。

关于问题中发布的代码,标记为“数据访问层”的代码充当业务层使用的通用抽象。通过这样做,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<int, Product> _products = new Dictionary<int, Product>()
    
         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);
    

尽管此示例使用接口,但同样适用于基类的使用。美妙之处在于,现在我可以将SqlProductRepositoryMockProductRepository 输入AwesomeBusinessLogic 并且不必更改AwesomeBusinessLogic 的任何内容。如果出现另一种情况,所需要的只是IProductRepository 的新实现,AwesomeBusinessLogic 仍将处理它而无需更改,因为它仅通过接口访问存储库。

【讨论】:

现在您可以实现访问不同数据库的 DALMicrosoft 企业库在 DAL 层为我完成这项工作。 是的,MS Enterprise 库将帮助您实现这一目标,但是如果您决定将您的存储库现在公开为 Web 服务,如 WCF 数据服务(也称为 ado.net 数据服务),该怎么办? ??如果您已将存储库创建为接口,那么替换它很容易——这就是全部内容...希望您现在清楚。 没有得到你..老实说。如何在您的架构中包含 WCF?好的,为什么 WCF 不能直接与 DataBase 层交互?每一层都是一个独立的项目。【参考方案6】:

前面所有的答案可能都说明了抽象层的需求,但我还是想补充一些自己的想法。

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

namespace ***

    public class ContactDbService
    
        public Contact GetContactByID(Guid contactID)
        
            //Fetch a contact from DB
        
    

联系 BLL 服务:

namespace ***

    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;

        
    

没有定义接口/抽象类。

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

    代码交流: 想象一下,如果你的项目涉及到,你的服务可能有很多不同的方法,一个维护者(除了你)怎么可能知道你的服务是做什么的呢?他是否必须阅读您的整个服务才能修复像 InvalidCastOperation 这样的小错误? 通过查看界面,人们将立即了解服务的功能(至少)。

    单元测试

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

    更容易改变:

    通过只引用其他类中的接口/抽象类,您可以在以后轻松替换那些接口实现,而无需太多工作。

【讨论】:

通过只引用其他类中的接口/抽象类,您以后可以轻松替换那些接口实现,而无需太多工作。这可以通过直接在DAL 层。为什么是接口? 通过查看界面,人们将立即了解服务的功能(至少)。 我们通常根据模块和特定需求创建功能名称。为什么是接口? 我们通常根据模块和具体需要创建函数名称。为什么是接口?如果我没有对您的功能的任何描述,我怎么知道您的班级可以做什么?为了知道我应该从 BLL 中调用什么,我是否必须搜索并阅读您类的所有函数? 你是想在函数的标题部分说 cmets 吗? 不,我的意思是,假设您开发服务,稍后我将接您的工作并继续。我怎么知道你们的服务细节? 基本上有两种方式。 1. 按 Ctl + M + o 这将只显示隐藏在 DAL 层中的函数名称和函数定义。 2. 实例化类和类型对象。这将向您显示包含您定义的函数 cmets 摘要的完整函数列表。为什么是接口呢?【参考方案7】:

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

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

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

【讨论】:

为什么要为 Interface/Abstract 类创建依赖项。基本需求是什么?有什么安全措施吗?【参考方案8】:

抽象使您能够快速进行重构。考虑不使用 SQL 服务器,而是决定使用其他提供程序;如果您没有数据访问层,那么您需要进行巨大的重构,因为您直接调用数据访问方法。但是如果你有一个数据访问层,你只需要编写一个新的数据访问层,继承自你的抽象数据访问层,你不会改变业务层中的任何东西。

【讨论】:

以上是关于为啥我们的项目需要接口层/抽象类? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

java 中interface和抽象类的区别

Java 接口和抽象类--缺省模式

为啥继承具有名称签名的接口成员的 C# 抽象类至少需要实现其中一个?

如果我们可以简单地覆盖超类的方法或使用抽象类,为啥还要使用接口? [复制]

为啥不抽象政策?

java随笔:浅谈抽象类与接口