My Previous Post talked about a sample Specification pattern implementation. Today, during a discussion with some team members, I had the revelation of how fluent interfaces are really built and how they operate under Closure of Operations. So I decided to expand my previous sample code with a more operators on the spec class, and I came up with a very powerful fluent interface for creating specifications.
Here is the example I coded into my spike, to illustrate a fluent interface. Note that I changed nothing in my implementation of the ISpecification<t> or base Specification<t> from yesterday - other than to add the "Or" and "Not" specifications. The fluent interface was already there and available!
//show the real power of Closure Of Operations, in creating a fluent interface!
ISpecification<Foo> chainedSpec = equalSpec
.And(passingSpec.And(trueSpec))
.Or(passingNotSpec)
.Not(failingSpec.Or(falseSpec))
.And
(
passingSpec.Or
(
failingSpec.Not(falseSpec)
)
);
I'll leave it to you, the reader, to implement the "Or" and "Not" specification classes. It should be pretty simple, based on the code I posted yesterday.
I can see how we could easily use an a "Closed" interface like this, to create a more fluent implementation of business rules and logic. I've often implemented multiple if-then statements in order to evaluate equality and equivalence, via multiple methods and a lot of ugly code. This specification implementation may be the answer to that ugliness.
And suddenly, Ayende's UnitOfWork and NHibernate's ICriteria make a lot more sense to me... I love those "AHA!" moments. 