【问题标题】:Rhino Mocks, Dependency Injection, and Separation of ConcernsRhino Mocks、依赖注入和关注点分离
【发布时间】:2010-03-18 23:03:04
【问题描述】:

我是模拟和依赖注入的新手,需要一些指导。

我的应用程序使用典型的 N 层架构,其中 BLL 引用 DAL,UI 引用 BLL 但不引用 DAL。很直接。

比如说,我有以下类:

class MyDataAccess : IMyDataAccess {}
class MyBusinessLogic {}

每个都存在于一个单独的程序集中。

我想在 MyBusinessLogic 的测试中模拟 MyDataAccess。因此,我在 MyBusinessLogic 类中添加了一个构造函数,以采用 IMyDataAccess 参数进行依赖注入。但是现在当我尝试在 UI 层上创建 MyBusinessLogic 的实例时,它需要对 DAL 的引用。

我以为我可以在 MyBusinessLogic 上定义一个默认构造函数来设置默认的 IMyDataAccess 实现,但这不仅看起来像代码错误,而且实际上并没有解决问题。我仍然在签名中有一个带有 IMyDataAccess 的公共构造函数。所以 UI 层仍然需要引用 DAL 才能编译。

我正在尝试的一个可能的解决方案是使用 IMyDataAccess 参数为 MyBusinessLogic 创建一个内部构造函数。然后我可以使用测试项目中的访问器来调用构造函数。但是还是有那种味道。

这里的常见解决方案是什么。我一定是做错了什么。我该如何改进架构?

【问题讨论】:

    标签: dependency-injection rhino-mocks n-tier-architecture separation-of-concerns


    【解决方案1】:

    你可以这样定义你的类:

    public class MainForm : Form
    {
        private readonly businessLogic;
    
        public MainForm(IBusinessLogic businessLogic)
        {
            this.businessLogic = businessLogic;
        }
    }
    
    public class BusinessLogic : IBusinessLogic
    {
        private IDataLayer dataLayer;
    
        public BusinessLogic(IDataLayer dataLayer)
        {
            this.dataLayer = dataLayer;
        }
    }
    
    public class DataLayer : IDataLayer
    {
        public DataLayer(string connectionString)
        {
        }
    }
    

    请注意这里的主窗体如何不知道 DAL。现在我们确实需要一段知道所有类的代码,以便它们可以连接在一起。这通常在应用程序开始时完成:

    public static void Main(string[] args)
    {
       var dataLayer = new DataLayer("foo");
       var businessLogic = new BusinessLogic(dataLayer);
       var mainForm = new MainForm(businessLogic);
    
       Application.Run(mainForm);
    }
    

    当然,这是一个简化的例子。如果在实践中你有几十个或几百个类,那么这种启动布线会变得非常庞大和复杂,尤其是在循环依赖发挥作用时。这就是为什么创建依赖注入框架来用 XML 配置文件、代码配置或 .NET 属性替换该代码的原因。不过基本思路是一样的。

    .NET 的依赖注入框架示例:AutoFacCastleSpring.NETStructureMapNinjectManaged Extensibility Framework

    【讨论】:

    • 使用 IoC 容器对性能有何影响?我非常喜欢这个解决方案,目前正在玩 Castle。
    • @whatispunk:使用 IoC 容器不会影响启动后的性能。如果由于连接在一起的对象数量过多而导致启动时间过长,您通常在容器中具有启用延迟加载的功能(例如,托管可扩展性框架的 System.Lazy<T>)。
    • 有道理。就我而言,我正在开发一个 Web 应用程序,因此启动时间并不重要。感谢您的帮助。
    【解决方案2】:

    我昨天answered 提出了一个关于如何structure a .NET solution 的问题,我认为这可以解决您的问题。

    在我的回答中,您的关键点应该是没有一个“实现”程序集引用其他“实现”程序集。这应该可以解决您的关注点分离问题。

    此外,该结构还几乎要求使用依赖注入,并且非常适合单元测试和模拟的使用。

    希望对你有帮助。

    【讨论】:

    • 这听起来是一个非常棒的解决方案,但我认为要说服我的团队的其他成员重组我们的整个应用程序将是一项艰巨的任务。
    【解决方案3】:

    如果您想避免从 UI dll 中引用数据访问 dll,那么您可以将数据访问接口/基类提取到第三个库中,并让其他两个都引用它。

    【讨论】:

      猜你喜欢
      • 2013-03-28
      • 2022-07-15
      • 2021-11-19
      • 2017-07-17
      • 1970-01-01
      • 1970-01-01
      • 2018-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多