我有一个分层的解决方案如下:
- UI(用户界面)
- BLL(业务逻辑层)
- DAL(数据访问层)
- SharedEntities(仅具有实体 POCO 的 VS 项目)
我希望 BLL 有一个名为 GetProductList() 的服务,该服务在我的 DAL 层中实现。我想过在 BLL 和 DAL 实现中定义一个接口,如下所示:
选项 A:
// Interface defined in BLL
public interface IDataServices
{
List<Product> GetProductList();
}
// Interface implemented in DAL
public class DataServices : IDataServices
{
Public List<Product> GetProductList()
{
return //do some database work here and return List<Product>;
}
}
如果我想在 DAL 中实现这一点,那么我必须让 DAL 项目引用 BLL 项目才能看到 IDataServices 的接口定义。或者,我可以在 DAL 中复制接口定义,但最终我会使用重复的代码来维护(BLL 和 DAL 中的接口定义相同)。
选项 B:我可以做到这一点的另一种方法是忘记接口的想法,只需在 UI 可以使用的 BLL 中进行以下具体的类和方法调用:
// Concrete class defined in the BLL
public class DataServices
{
Public List<Product> GetProductList()
{
DAL aDAL = new DAL();
Return (aDAL.GetProductList());
}
}
这很容易,但是 BLL 看到了 DAL 并引用了它,但这真的是一件坏事吗?只要 BLL 不使用任何数据库对象(即数据源、连接字符串等)来满足请求并且 DAL 符合匹配我在 BLL DataServices 类中定义的服务名称,这还不够吗?我听到的所有关于交换另一个数据库引擎的讨论仍然可以通过确保下一个 DAL 提供 BLL 在 DataServices 类中标识的相同服务来完成,例如 GetProductList()。在这个设置中,UI 仍然不知道任何关于 DAL 的信息,而 DAL 也不知道任何关于 BLL 的信息。如果我考虑使用依赖注入来避免在 BLL 中实例化 DAL 的想法,那将意味着在 UI 中实例化它以传递给 BLL。
选项 C:我简要查看了 Unity Container,但该工具建议在入口点预先注册所有接口和具体类,这本来是 UI,这反过来又使 UI 对 BLL 和 DAL 可见似乎更糟。我看到了使用 MEF 和 Unity 来解决入口点看到所有层的问题的参考,但也看到如果你这样做,你就不能真正对这样的配置进行单元测试。与选项 B 相比,似乎需要大量工作和复杂性。
选项 D:我想到的另一个选项是在 BLL 和 DAL 之间创建一个外观层(另一个 VS 项目)。这似乎没有多大意义,除非我最终得到了很多与 BLL 无关的 DAL 方法,因此它们必须被隐藏;允许 DAL Facade 仅显示 BLL 需要的内容。如果我要换入另一个数据库,我仍然必须根据 BLL 的需要创建外观所需的方法,正如我在选项 B 中提到的那样。
因此,基于这一切,我正在考虑选择选项 B,但我想在这里获得一些社区意见。我还能做什么满足以下条件:
- 1) 不让 UI 看到 DAL
- 2) 不让 DAL 看到 BLL
- 3) 该解决方案仍然允许对所有层进行单元测试