我们通常在项目中使用抽象函数/接口。为什么真的需要它?为什么我们不能只去商业逻辑层,数据访问层和表示层
演示层中的功能:
abc();
业务逻辑层中的功能:
public void abc()
{
//Preparing the list
}
数据访问层中的功能:
public abstract void abc();
数据访问SQLServer层中的功能:
public override void abc()
{
//Connection with database
}
问题是:为什么需要数据访问层?
答案 0 :(得分:2)
理解这一点的最简单方法是imo,它是对DataLayer
的抽象。
您已设置了从xml
文件中检索数据的功能。但是有一天你的产品会缩小,xml
就像数据存储一样。所以你传递给一些嵌入式数据库:sqlite
。但有一天,您需要在某些企业环境中重用您的库。所以现在您需要开发sqlserver
,oracle
,webservice
的访问权限....在所有这些更改中,您需要更改不仅代码实际上访问数据,但实际消费的代码也是如此。多年来您在客户端上首次使用xml
数据访问并且对它感到满意的代码呢?反向兼容性怎么样?
如果没有直接解决大部分问题,那么抽象可以解决大部分问题,但绝对会使你的应用程序变得可扩展,并且对变化更具抵抗力,在我们的世界中,有时过于频繁地发生。
答案 1 :(得分:2)
通常,如果在代码中使用接口,那么您将以依赖注入的形式获得代码可操作性。
这将帮助您在某些情况下替换部分实现,例如在单元测试期间提供Mock对象。
答案 2 :(得分:1)
为什么接口: 您是否曾在c#中使用使用: 使用(表格f =新表格()) { }
在这里,您将看到只能使用实现IDisposable接口的使用中的那些类。
彼此不了解的两件事只能使用Interfaces相互交互。 接口保证“某些”功能肯定是通过这种类型实现的。
为什么分层:
这样你就可以拥有单独的dll,它们可以让你在不同的应用程序中重用。
基本上所有这些都用于代码重用和性能提升。
答案 3 :(得分:0)
我认为你在谈论Facade层。
这是一个可选图层,它将简化业务层的功能。让我们想象一下,你有一个ProductManager和CategoryManager,你想做一个涉及使用两者的特定动作(例如,让我在所有类别中获得前5个产品)然后你可以使用一个使用ProductManager和CategoryManager的外观层。
灵感来自Facade Pattern。
答案 4 :(得分:0)
抽象有助于创建功能,无论是通过基类,接口还是组合,如果使用得当,都会对维护,可读性和代码的可重用性产生奇迹。
关于问题中发布的代码,标记为“数据访问层”的代码充当业务层要使用的通用抽象。通过这样做,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);
}
}
尽管此示例使用接口,但同样适用于基类的使用。美妙的是,现在我可以将SqlProductRepository
或MockProductRepository
提供给AwesomeBusinessLogic
,而则无需更改AwesomeBusinessLogic
的任何内容。如果出现另一个案例,那么所需要的只是IProductRepository
的新实现,而AwesomeBusinessLogic
仍将处理它而不进行更改,因为它只通过接口访问存储库。
答案 5 :(得分:0)
所有以前的答案都可以解释抽象图层的需求,但我仍然想补充一些想法。
让我们说在我们的项目中,我们在每一层中只有一个服务实现。例如,我有一个联系人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;
}
}
}
没有定义接口/抽象类。
如果我们这样做,会有一些明显的缺点。
单元测试
您可以使用假/模拟服务测试您的逻辑,以提前检测错误,并防止以后发生回归错误。
更容易更改:
通过仅通过其他类中的接口/抽象类进行引用,您可以在不需要太多工作的情况下轻松替换这些接口实现。
答案 6 :(得分:0)
抽象类或接口实际上不是一个单独的层 - 它应该是业务逻辑层的一部分,它定义了实际数据访问层(例如SQL数据存储库)需要实现以提供数据的接口访问您的业务层的服务。
如果没有此接口,您的业务层将直接依赖于SQL层,而接口将删除此依赖关系:您将抽象类或接口放入业务逻辑层。然后SQL层(例如,单独的程序集)实现抽象类/接口。这样,SQL层依赖于业务层,而不是相反。
结果是一个灵活的应用程序,具有可以与多个数据存储库一起使用的独立业务层 - 它所需要的只是一个实现业务层定义的接口的层。它实际上并不只是关于数据存储库 - 您的业务层不应该依赖于上下文(asp.net与控制台应用程序与服务等),它不应该依赖于用户界面类,模块接口与您的业务应用程序等。
答案 7 :(得分:0)
抽象使您可以快速进行重构。想想使用其他提供程序而不是使用SQL服务器;如果你没有数据访问层,那么你要做一个巨大的重构,因为你直接调用数据访问方法。但是,如果您有数据访问层,则只需编写一个新的数据访问层,继承自抽象数据访问层,并且不会更改业务层中的任何内容。