在哪个层中,Specification Pattern对象应该是"new'ed up"?

Mic*_*thy 7 domain-driven-design specification-pattern n-layer application-layer

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

我的问题是,在一个n层架构中,我应该在哪些规范中获得"新建"?

  1. 我可以将它们放在我的服务层(也就是说,应用层,它有时被称为......基本上,.aspx代码隐藏的东西会与之交谈),但我觉得通过这样做,我让业务规则漏掉了域名.如果以其他方式(除了服务层)访问域对象,则域对象无法强制执行自己的业务规则.

  2. 我可以通过构造函数注入将规范注入到我的Model类中.但同样,这感觉"错误".我觉得唯一应该注入Model类的是"服务",比如缓存,日志记录,脏标记跟踪等等......如果你能避免它,那么使用Aspects而不是乱丢模型的构造函数具有大量服务接口的类.

  3. 我可以通过方法注入(有时称为"Double Dispatch")注入规范,并明确地使用该方法封装注入的规范以强制执行其业务规则.

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

除此之外,相关规范要求存储库以确定它是否"满意".

这可能会导致性能问题,尤其是 如果我使用构造函数注入b/c消耗代码可以调用一个可能包装规范的属性,并且反过来调用数据库.

所以任何想法/想法/链接到文章?

新产品和使用规格的最佳位置在哪里?

aut*_*att 7

简短回答:

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

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

你的规格应该放在哪里,它们应该在哪里新建?

就像您的存储库接口一样,您的规范应该存在于域层中,因为它们毕竟是特定于域的.SO上有一个问题,就存储库接口讨论了这个问题.

他们应该在哪里新装?好吧,我在我的存储库中使用LinqSpecs,并且我的存储库中大多数都有三种方法:

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);
}
Run Code Online (Sandbox Code Playgroud)

我的其余查询都是在我的服务层构建的.这使得存储库不会因GetUserByEmail,GetUserById,GetUserByStatus等方法而变得臃肿.在我的服务中,我新建了我的规范并将它们传递给我的存储库的FindAll或FindOne方法.例如:

public User GetUserByEmail(string email)
{
    var withEmail = new UserByEmail(email); // the specification
    return userRepository.FindOne(withEmail);
}
Run Code Online (Sandbox Code Playgroud)

这是规格:

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
}
Run Code Online (Sandbox Code Playgroud)

所以为了回答你的问题,规范在服务层(在我的书中)中是新的.

我觉得唯一应该注入Model类的是"服务"

IMO你不应该向域实体注入任何东西.

除此之外,相关规范要求存储库以确定它是否"满意".

那是代码味道.我会在那里检查你的代码.规范绝对不需要存储库.

  • 您将规范传递给存储库,例如通过FindOne(规范)或FindAll(规范).如果将存储库注入规范,则存在创建循环引用的危险,这可能会导致问题. (2认同)

bst*_*ack 6

规范是业务规则的实现检查.它必须存在于域层完全停止.

由于每个代码库都不同,因此很难详细说明如何执行此操作,但我认为任何业务逻辑都需要在域层中,而不是其他任何地方.此业务逻辑需要完全可测试,并且可以从UI,数据库,外部服务和其他非域依赖项中松散地进行耦合.所以我肯定会排除上面的1,2和3.

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

最后,我的答案是假设您正在处理的系统至少有些复杂.如果它是一个非常简单的系统,域驱动设计作为一个概念可能过于顶级.然而,无论我认为代码库如何,都应该尊重一些概念,例如可测试性,可读性,SoC等.