Domain driven design 规范模式对象应位于哪一层;新';ed up";?

Domain driven design 规范模式对象应位于哪一层;新';ed up";?,domain-driven-design,specification-pattern,n-layer,application-layer,Domain Driven Design,Specification Pattern,N Layer,Application Layer,所以,我在这里查看了一些关于规范模式的帖子,但还没有找到这个问题的答案 我的问题是,在n层体系结构中,me规范究竟应该在哪里“更新” 我可以把它们放在我的服务层(也称为应用层,它有时被称为…基本上,一个.aspx代码背后的东西会与之对话),但我觉得这样做,我让业务规则泄漏出了域。如果以其他方式访问域对象(除服务层外),则域对象无法强制执行其自己的业务规则 我可以通过构造函数注入将规范注入到我的模型类中。但同样,这感觉“不对”。我觉得唯一应该注入模型类的是“服务”,比如缓存、日志记录、脏标志跟踪等

所以,我在这里查看了一些关于规范模式的帖子,但还没有找到这个问题的答案

我的问题是,在n层体系结构中,me规范究竟应该在哪里“更新”

  • 我可以把它们放在我的服务层(也称为应用层,它有时被称为…基本上,一个.aspx代码背后的东西会与之对话),但我觉得这样做,我让业务规则泄漏出了域。如果以其他方式访问域对象(除服务层外),则域对象无法强制执行其自己的业务规则

  • 我可以通过构造函数注入将规范注入到我的模型类中。但同样,这感觉“不对”。我觉得唯一应该注入模型类的是“服务”,比如缓存、日志记录、脏标志跟踪等等。。。如果可以避免的话,可以使用方面,而不是将大量服务接口浪费在模型类的构造函数中

  • 我可以通过方法注入(有时称为“双重分派”)注入规范,并显式地让该方法封装注入的规范以强制执行其业务规则

  • 创建一个“域服务”类,该类将通过构造函数注入获取规范,然后让服务层使用域服务来协调域对象。这对我来说似乎没问题,因为规范强制执行的规则仍然在“域”中,并且域服务类的命名与它所协调的域对象非常相似。这里的问题是,我觉得我正在编写大量的类和代码,只是为了“正确地”实现规范模式

  • 此外,所讨论的规范需要一个存储库来确定它是否“满足”

    这可能会导致性能问题,特别是如果我使用构造函数注入,b/c消费代码可能会调用一个可能包装规范的属性,而该属性反过来又调用数据库

    有什么想法/想法/文章链接吗


    哪里是创建和使用规范的最佳位置?

    规范是对业务规则的实现检查。它必须存在于域层中

    很难给出具体的操作方法,因为每个代码库都是不同的,但我认为任何业务逻辑都需要在域层,而不是其他任何地方。此业务逻辑需要完全可测试,并与UI、数据库、外部服务和其他非域依赖项松散耦合。所以我肯定会排除上面的1、2和3

    4是一个选项,至少该规范将存在于您的域层中。然而,规范的更新实际上又取决于实现。我们通常使用依赖注入,因此几乎所有对象的更新都是通过IOC容器和相应的引导代码执行的(即,我们通常流畅地连接应用程序)。但是,我们永远不会将业务逻辑直接链接到UI模型类等。我们通常在UI和域等事物之间有轮廓/边界。我们通常定义域服务契约,然后可以由外部层(如UI等)使用


    最后,我的答案是假设您正在使用的系统至少在某种程度上是复杂的。如果它是一个非常简单的系统,那么领域驱动设计作为一个概念可能太过分了。然而,在我看来,不管代码库是什么,诸如可测试性、可读性、SoC等概念都应该得到尊重。

    简短回答:

    您主要在服务层中使用规范,因此存在

    长答案: 首先,这里有两个问题:

    你的规格应该放在哪里,新的应该放在哪里

    就像您的存储库接口一样,您的规范应该位于域层,因为它们毕竟是特定于域的。关于存储库接口,有一篇文章对此进行了讨论

    但是,它们应该在哪里更新呢?嗯,我在我的存储库中使用,并且在我的存储库中通常有三种方法:

    public interface ILinqSpecsRepository<T>
    {
        IEnumerable<T> FindAll(Specification<T> specification);
        IEnumerable<T> FindAll<TRelated>(Specification<T> specification, Expression<Func<T, TRelated>> fetchExpression);
        T FindOne(Specification<T> specification);
    }
    
    以下是规格:

    public class UserByEmail : Specification<User>
    {
        private readonly string email;
    
        public UserByEmail(string email)
        {
            this.email = email;
        }
    
        #region Overrides of Specification<User>
    
        public override Expression<Func<User, bool>> IsSatisfiedBy()
        {
            return x => x.Email == email;
        }
    
        #endregion
    }
    
    public类UserByEmail:规范
    {
    私人只读字符串电子邮件;
    公共用户通过电子邮件(字符串电子邮件)
    {
    this.email=电子邮件;
    }
    #规范的区域覆盖
    公共重写表达式IsSatifiedBy()
    {
    返回x=>x.Email==Email;
    }
    #端区
    }
    
    因此,为了回答您的问题,规范在服务层中是新的(在我的书中)

    我觉得这是唯一应该注入模型类的东西 是“服务”

    在我看来,您不应该向域实体注入任何内容

    此外,相关规范还需要一个存储库 以确定是否“满意”


    这是一个好主意。我会在那里检查你的代码。规范绝对不需要存储库。

    不太确定向规范中注入存储库是否是代码气味。检查此StackOverflow讨论:。规范和域服务之间的相似性可能非常相似,特别是当您试图实施/证明的规则恰好依赖于首先通过存储库获取信息时。您可以通过FindOne(spec)或FindAll(spec)将规范传递给存储库。如果将存储库注入规范,则有创建循环引用的危险,这可能会导致问题。仅供参考,我会在需要时将规范注入服务。
    public class UserByEmail : Specification<User>
    {
        private readonly string email;
    
        public UserByEmail(string email)
        {
            this.email = email;
        }
    
        #region Overrides of Specification<User>
    
        public override Expression<Func<User, bool>> IsSatisfiedBy()
        {
            return x => x.Email == email;
        }
    
        #endregion
    }