使用规范模式

发布于 2024-08-26 12:05:23 字数 550 浏览 5 评论 0原文

与任何设计模式一样,规范模式 是一个很棒的概念,但很容易被热心的架构师/开发人员过度使用。

我即将开始开发一个新应用程序(.NET 和 C#),并且非常喜欢规范模式的概念,并且渴望充分利用它。然而,在我全力以赴之前,我真的很想知道是否有人可以分享使用 规范模式

理想情况下,我想看看其他人在

  • 根据规范模式编写单元测试
  • 时是否遇到问题决定规范应该位于哪一层(存储库、服务、域等)
  • 当一个简单的 if 声明会完成这项工作
  • 等吗?

提前致谢

Like any design pattern the Specification Pattern is a great concept but susceptible to overuse by an eager architect/developer.

I am about to commence development on a new application (.NET & C#) and really like the concept of the Specification Pattern and am keen to make full use of it. However before I go in all guns blazing I would be really interested in knowing if anyone could share the pain points that experienced when use the Specification Pattern in developing an application.

Ideally I'm looking to see if others have had issues in

  • Writing unit tests against the specification pattern
  • Deciding which layer the specifications should live in (Repository, Service, Domain, etc)
  • Using it everywhere when a simple if statement would have done the job
  • etc?

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

二智少女 2024-09-02 12:05:23

我不认为 LINQ 可以替代规范模式。请记住,规范最好用于封装业务逻辑。因此,如果我的业务需求之一要求我获得所有有价值的客户的多种功能,我的 Linq 语句可能如下所示:

var valuedCustomers = Customers.Where(c => c.Orders.Count > 15 && c.Active).ToList();

我可以在我的应用程序中键入此语句,但如果我想附加到客户必须拥有的规则,该怎么办在某个日期之前加入?好吧,现在我必须检查我的应用程序并更改 Linq。或者如果我的对象图发生变化(尽管这不应该是使用该模式的唯一原因)。相反,当我可以做这样的事情时,

var valuedCustomers = Customers.Where(new ValuedCustomerRule.IsSatisfied()).ToList();

我同意该模式已被过度使用,但它对于在整个系统中显示的业务规则非常有帮助,这样当这些规则发生变化时您就不会受到影响。对我来说,这类似于在应用程序代码中保留 SQL 查询。

I do not believe LINQ is a replacement for the Specification pattern. Remember that a specification is best used to encapsulate business logic. So if one of my business requirements has me get all valued customers for several features my Linq statement may look like this:

var valuedCustomers = Customers.Where(c => c.Orders.Count > 15 && c.Active).ToList();

I can type out this statement all over my application but what if I want to append to that rule that the customer has to have joined before some date? Well, now I have to go all over my application and change the Linq. Or if my object graph changes (though this shouldn't be the sole reason for using the pattern). When instead I could just do something like this

var valuedCustomers = Customers.Where(new ValuedCustomerRule.IsSatisfied()).ToList();

I agree that the pattern is over used but it is very helpful for business rules that show up throughout your system so you don't get bitten when those rules change. To me it is similar to leaving SQL queries all over your application code.

最终幸福 2024-09-02 12:05:23

正如 David 在评论中指出的那样,现在可以使用 LINQ 之类的工具更简洁地实现规范中的许多有用内容。

您可以即时创建任意规范,而不是新的规范类型:
GetCustomers().Where(customer => customer.IsActive && customer.City == "Oakland");

然而,这并不能完全替代规范,原因有几个:

  1. 返回所有客户后,排序/过滤发生在消费类中。如果您正在处理内存中对象以外的任何对象,那么这是次优的(LINQ-to-SQL 等是例外,因为它们编译和优化查询并在服务器/远程端执行它们,仅返回所需的结果)。
  2. 如果您公开集合并将规范留给 LINQ 查询,那么您的 API 对任何查询都是开放的。如果您想限制可以检索的内容或数量,则需要一组用于查询的规范。

当然没有必要到处使用它,而且很可能你根本不需要它;我不知道您的域名或您正在做什么。

我认为最好的建议是不要看起来使用它。当您开始编写一个看起来像您链接到的文章中的第一个示例的类时,您会看到它何时是必要的。

只需将其保存在您的心理模式存储库中,以便在需要时可以使用;如果你从不使用它,那只意味着你不需要它,那也没关系。

层的选择取决于规格和用途的性质。在许多情况下,它们是支持服务层的助手,但在某些情况下,它们封装了领域逻辑。

至于单元测试,请记住您的规范是单元或包含单元。不要测试接受具有所有可能的规范组合的规范的方法;测试规范本身以确保它们的行为符合预期,然后您可以在许多方法和类中放心地重用相同的规范。

希望这有点帮助。

As David pointed out in his comment, a lot of what is useful about specification can now be more succinctly achieved with the likes of LINQ.

Instead of a new specification type, you can create arbitrary specifications on-the-fly:
GetCustomers().Where(customer => customer.IsActive && customer.City == "Oakland");

This is not a complete replacement for specification, however, for a couple of reasons:

  1. The sorting/filtering happens in the consuming class after returning all customers. If you are dealing with anything other than in-memory objects, this is sub-optimal (LINQ-to-SQL and the like are exceptions because they compile and optimize queries and execute them on the server/remote side, returning only the desired results).
  2. Your API is wide-open to any query if you expose collections and leave the specification to LINQ queries. If you want to constrain what or how much can be retrieved, you'll need a set of specifications with which to query.

There is certainly no need to use it everywhere, and it is very possible that you won't need it at all; I don't know your domain or what you're working on.

I think the best advice is not to look to use it. You'll see when it is warranted, most likely when you start writing a class that looks like the first example in the article to which you linked.

Just keep it in your mental pattern repository so you've got if you need it; if you never use it, it only means that you didn't need it, and that is fine.

The choice of layer is subject to the nature of the specifications and usage. In many cases they are helpers in support of a service layer, but in some cases they encapsulate domain logic.

As for unit testing, remember that your specifications are units or contain units. Don't test a method that accepts a specification with all possible combinations of specification; test the specifications themselves to make sure that they behave as expected, and then you can reuse the same specifications with confidence in many methods and classes.

Hope that's a bit helpful.

猫烠⑼条掵仅有一顆心 2024-09-02 12:05:23

更新的答案:
我同意 Wix 的观点,LINQ 并不能替代规范模式。我没有足够的声誉来向 Wix 答案添加评论,我只是作为答案进行回复。

根据本文,规范主要用于将域对象与语句进行匹配。尽管规范在与域对象匹配时返回 true/false,但这并不意味着规范是
建议在代码中封装任何布尔条件。

我将进一步继续Wix的回答。如果您有定义的 ValuedCustomer 规范,那么您有不同的可能性使用规则:

   var valuedCustomer = new ValuedCustomerSpecification();
   //1. You can use this statement to check if a customer is valued or not in your domain
   Customer customer = ....
   if(valuedCustomer.IsSatisfiedBy(customer))
   
   //2. You can use it to get just valued customers from repository, 
   var valuedCustomers = repository.Get(valuedCustomer);
   
   //3. You can combine it with other specifications to create composite specifications. Following syntax can vary with implementation
   var seniorValuedCustomer = valuedCustomer.And(seniorCustomer)

我对 论文 是用户可以与规范交互以实现其目标,前提是有需要并且您的应用程序 UI 允许。

上述论文还提到了何时不使用规范模式。

Updated answer:
I agree with Wix, LINQ is not replacement for Specification pattern. I do not have enough reputation to add comment to Wix answer, I'm just replying as an answer.

As per this paper specifications are primarily used to match a domain object against a statement. Though specifications return true/false when matching against a domain object but that does not mean specifications are
proposed to encapsulate any boolean condition in your code.

I will carry on Wix's answer's further. If you have a defined ValuedCustomer specification, then you have different possibilities to use rule:

   var valuedCustomer = new ValuedCustomerSpecification();
   //1. You can use this statement to check if a customer is valued or not in your domain
   Customer customer = ....
   if(valuedCustomer.IsSatisfiedBy(customer))
   
   //2. You can use it to get just valued customers from repository, 
   var valuedCustomers = repository.Get(valuedCustomer);
   
   //3. You can combine it with other specifications to create composite specifications. Following syntax can vary with implementation
   var seniorValuedCustomer = valuedCustomer.And(seniorCustomer)

My understanding from paper is that user can interact with specifications to achieve their objectives provided there is a need for it and your app UI allows it.

Above mentioned paper also mention when not to use specification patterns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文