문제

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

도움이 되었습니까?

해결책

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.

다른 팁

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.

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 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 a ValuedCustomer specification then you have different posibility 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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top