【问题标题】:DDD and IOC ContainersDDD 和 IOC 容器
【发布时间】:2010-05-24 12:47:44
【问题描述】:

我是 DDD 的新手,我尝试使用 IOC 来放松我的紧密耦合层 :)

我的 C# Web 应用程序由 UIdomainpersistence 层组成。我的 persistence 层引用了我的 domain 层并包含我的具体存储库实现和休眠映射。目前我的 UI 引用了我的 domain 层。

我的问题:如何使用 IOC 容器将持久层中的具体类注入 层?这是否意味着我的 UI 也应该引用我的 persistence 层?

【问题讨论】:

    标签: c# domain-driven-design ioc-container


    【解决方案1】:

    Dave 是对的,DI 和 IOC 的目的是松散耦合系统的组件。

    您的 UI 应该只知道您的域,您的域应该只知道您的 Persistence,而您的 Persistence 不应该知道其他任何人。

    良好的 .NET IoC 容器是 StructureMap(我的首选)、Ninject 和 Castle Windsor。

    有多种实现 DI/IoC 的方式,最首选的方式是使用接口。

    你会有一个持久层的接口:

    public interface IPersistantStorage
    {
        List<Foo> GetStuff();
        void AddStuff(Foo f);
    }
    

    同样适用于您的域层:

    public interface IDomainManager
    {
        List<Foo> GetStuff();
        void AddStuff(Foo f);
    }
    

    然后为每个实现具体的类。

    然后,您选择的 IoC 容器会将具体类“注入”到构造函数中。

    这是一个如何使用 StructureMap 的示例:

    public class SomeClassInUILayerThanNeedsToGetSomeThing
    {
         IDomainManager domain;
    
         public SomeClassInUILayerThanNeedsToGetSomeThing(IDomainManager realDomain)
         {
             this.domain = realDomain;
         }
    
         public List<Foo> GetSomethingFromSomewhere()
         {
             return domain.GetStuff();
         }
    }
    

    然后在 StructureMap 引导程序中(通常在您的应用程序启动事件中调用 - Global.asax)

    public static void ConfigureIoCFramework()
            {
                ObjectFactory.Initialize(x =>
                {
                       x.For<IDomainManager>().Use<DomainManager>();
                       x.For<IPersistantStorage>.Use<NHibernateStorage>();
                });
            }
    

    您的 UI 所知道的是,它会调用一些实现某些接口的域类。 您的域所知道的是,它会调用一些实现某些接口的 Persistence 类。

    “如何”或这个“什么”由上面的 DI 容器处理。

    如何设置取决于您的系统。我通常有这样的设置:

    1. 网站 -> 引用 2 个程序集:通用(扩展方法、业务实体等)、服务(如 UI 中的调用点 - 缓存层到持久性存储等)
    2. 服务 -> 引用 1 个程序集:存储库
    3. 存储库 -> 不引用任何内容。

    然后我会将服务层的具体实现注入 UI,并将存储库的具体实现注入服务层。

    如果您随后查看解决方案属性,再查看 Web 项目,您只会看到 2 个依赖项。特别是,它不会依赖于持久层。

    如果您想传递对象,请考虑将表投影到 POCO(包含在 Common 程序集中)。

    【讨论】:

    • 我认为这个说法是错误的your Domain should only know about your Persistence。该域必须是从蓝皮书中忽略的持久性。我一直在解决这个问题是在域中保留一个接口,例如IFooRepository,并且在数据/持久化后期/存储库层中,你实现了这个接口。这意味着您的存储库层知道域,但域除了交互之外对存储库一无所知。我不会投反对票,因为我还在学习这些东西,但我会被纠正。
    【解决方案2】:

    不,我不会将持久性注入到模型或视图中。

    您确实需要一个位于视图和其余部分之间的单独服务层。服务层了解工作单元;它协调持久性和模型对象以实现用例。

    模型对象不需要知道哪个层使用它们。它们表达了领域概念。

    【讨论】:

    • 您是说我的“服务层”(如您所描述的)应该引用我的持久层和域层?
    • 是的,没错。包含控制器的视图将使用对一个或多个服务接口的引用来满足视图请求。服务使用持久层和模型层。即使您更改了视图技术,这种安排还有一个额外的好处,即保持您的服务可重用。
    • 太好了,这更有意义......但是 IOC 容器在哪里适合所有这些。他们通常说您从前端设置 IOC 容器,在我的例子中是 Web 应用程序。你能解释一下吗?
    • 不,前端没有设置IOC容器。这是一个服务器端功能。当我编写一个 Spring Web 应用程序时,有一个监听器在 Web 应用程序加载时实例化 IOC 容器,读取配置,实例化组件,并将它们连接在一起。我想 .NET 也有类似的东西。
    【解决方案3】:

    您的 UI 不应引用您的持久层。使用 IoC,您可以将较低层的关注点以“堆栈”排列方式注入到其上方的层中。

    因此,您的 IoC 配置会将持久性实现注入您的域层。除了用于保存和检索域对象的接口之外,域层应该不了解持久性。这些接口由持久层中的类/逻辑实现。

    【讨论】:

    • 所以我没有在任何地方引用我的持久层?...你只是在IOC容器中指定持久层组件名称,它会自动创建实例吗?
    • 是的。 IoC 的目的是“松散耦合”您的持久性和域层,以便它们之间没有静态引用。您不会在 Visual Studio 中“添加引用”。这允许您通过配置“插入”多个持久性实现中的任何一个。
    • 好的,我试过了。但随后 UI 开发人员需要解析域中的每个服务或对象,使用 var obj = = (FooService) kernel[typeof(FooService)];符号...
    • 这不是春天的方式。不知道你用的是什么IOC/DI框架,但是Spring中页面不调用服务;控制器会。
    • @MegaByte- 你的视图应该绑定到模型/视图模型,它们公开域对象(实体、DTO 等等)。控制器与你的域对象和业务逻辑所在的中间层进行通信。中间层从“下面”注入持久性实现。
    猜你喜欢
    • 2011-02-07
    • 2011-02-21
    • 1970-01-01
    • 2014-04-29
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多