所以,我在这里查看了一些关于规范模式的帖子,但还没有找到答案。
我的问题是,在n层架构中,我应该在哪些规范中获得“新建”?
我可以将它们放在我的服务层(也就是说,它有时被称为应用程序层......基本上是.aspx代码隐藏的东西会说话),但我觉得这样做,我是让业务规则泄漏出域。如果以其他方式(除了服务层)访问域对象,则域对象无法强制执行自己的业务规则。
我可以通过构造函数注入将规范注入到我的Model类中。但同样,这感觉“错误”。我觉得唯一应该注入Model类的是“服务”,比如缓存,日志记录,脏标记跟踪等等......如果你能避免它,那么使用Aspects而不是乱丢模型的构造函数具有大量服务接口的类。
我可以通过方法注入(有时称为“Double Dispatch”)注入规范,并明确地使用该方法封装注入的规范以强制执行其业务规则。
创建一个“域服务”类,它将通过构造函数注入获取规范,然后让服务层使用域服务来协调Domain对象。这对我来说似乎没问题,因为规范强制执行的规则仍然在“域”中,而Domain Service类的命名方式与它正在协调的Domain对象非常相似。这里的事情是我觉得我正在编写大量的类和代码,只是为了“正确”实现规范模式。
除此之外,相关规范需要一个存储库才能确定它是否“满意”。
这可能会导致性能问题,尤其是如果我使用构造函数注入b / c消耗代码可以调用一个可能包装规范的属性,并且反过来调用数据库。
那么任何想法/想法/链接到文章?
新手和使用规格的最佳位置在哪里?
答案 0 :(得分:7)
简答:
您主要在服务层使用规格,所以。
答案很长: 首先,这里有两个问题:
您的规格应该在哪里生活,哪些应该是新的?
就像您的存储库接口一样,您的规范应该存在于域层中,因为它们毕竟是特定于域的。有一个question on 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);
}
我的其余查询都是在我的服务层构建的。这使得存储库不会因GetUserByEmail,GetUserById,GetUserByStatus等方法而变得臃肿。 在我的服务中,我新建了我的规范并将它们传递给我的存储库的FindAll或FindOne方法。例如:
public User GetUserByEmail(string email)
{
var withEmail = new UserByEmail(email); // the specification
return userRepository.FindOne(withEmail);
}
这是规范:
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
}
所以为了回答你的问题,规格在服务层(在我的书中)中是新的。
我觉得唯一应该注入Model类的东西 是&#34;服务&#34;
IMO你不应该向域实体注入任何东西。
除此之外,相关规范需要一个存储库 为了确定它是否满足&#34;或不。
那是code smell。我会在那里检查你的代码。规范绝对不需要存储库。
答案 1 :(得分:6)
规范是业务规则的实现检查。它必须存在于域层完全停止。
由于每个代码库都不同,很难详细说明如何执行此操作,但我认为任何业务逻辑都需要在域层中,而不是其他任何地方。此业务逻辑需要完全可测试,并且可以从UI,数据库,外部服务和其他非域依赖项中松散地耦合。所以我肯定会排除上面的1,2和3。
4是一个选项,至少规范将存在于您的域层中。然而,规范的新增取决于实施。我们通常使用依赖注入,因此几乎所有对象的新增都是通过IOC容器和相应的自举代码来执行的(即我们通常可以流畅地连接应用程序)。但是,我们绝不会直接将业务逻辑直接链接到例如UI模型类等。我们通常在UI和域之间存在轮廓/边界。我们通常定义域服务契约,然后可以由外部层使用,例如UI等。
最后,我的回答是假设你正在进行的系统至少有些复杂。如果它是一个非常简单的系统,域驱动设计作为一个概念可能过于顶级。然而,无论我认为代码库如何,都应该尊重一些概念,例如可测试性,可读性,SoC等。