I intentionally omitted implementation details because at the moment I'd like to point you out:

The generics-enabled interface, which let you specify your own specification to combine.

The constructor, where you have to describe the actual specification you'll combine, specifying its class, its specification method (isSatisfiedBy in our example) and the class of the specification object (IOffice in our example).

The fluent-style interface methods for applying logical operators to actual specifications or other composite specifications.

9 comments:

I came to a similar conclusion regarding commons-collections predicates. Too bad there are no usable specification implementations out there.

The specifications look nice with the fluent-style interface.

Now, in order for specifications to be really useful, there has to be a way to map them to (alternative?) persistence technology queries. How would you propose to do that?

Lastly, I have found it useful to implement a sort of "Specification.validate" method which creates (or populates) an object with all the ways an object deviates from a specification. This is immensely useful for testing, as you can check what the reason was for an unexpected result much more easily that way.

I think it is nice and very similar to the one available in commons. The only disadvantage In *not* using commons is that commons has a lot more regarding the use of predicates that simple composite predicates.

If you take a look at the common collections you'll see such Util classes as ollectionUtils.select(java.util.Collection inputCollection, Predicate predicate) that select elements of a collection based on a predicate. There are similar one to creating Bags, Maps and Sets.

Then, there is also the Closure and Transformer operations you can use together with the predicates. Per example, you could create a generic closure operation that visits a list of Offices and make sure they perform with the Specification and if not do an action or return an object.

My point is that Predicates is just a small part of logical programming in commons so you way want to take a look at it and see what else could be interesting to extract.

> I think it is nice and very similar to the one available in commons.

Roni, it is not intended to be a duplicate of Commons Predicate, because with CompositeSpecification you can:

1) Use your own specifications, each with its proper interface.2) Compose them using a fluent interface.

> The only disadvantage In *not* using commons is that commons has a lot more > regarding the use of predicates that simple composite predicates.

Yes, you are right.However, I'm planning to integrate CompositeSpecification with Commons Predicate, in order to be used together with Commons Collections capabilities, without reinventing the wheel.I see two approaches:

If I have to choose I would be inclined to prefer AOP, but it seems you are more capable than I am at using AOP introductions. Is not that I don't like hooking with commons, it's just that I like code that is more "free" of external packeges.

I agree with you.However we overrated the problem: given that we know both interfaces in advance (the Predicate interface and the CompositeSpecification one) we can use a simple, plain, object adapter.

AOP introduction is instead still useful if we want to adapt the CompositeSpecification interface to specification interfaces provided by developers.Say you have a method in one of yours business objects:

public setCustomerSpecification(ProprietarySpecification spec);

You cannot use the CompositeSpecification here because you'd have to change the interface.An AOP mixin could be used to mix the CompositeSpecification interface and the ProprietarySpecification one.

What do you think?

> Is not that I don't like hooking with commons, it's just that I like code that > is more "free" of external packeges.

Again, I agree with you.Indeed, CompositeSpecification is implemented under the cover using Apache Commons ... however, they are interface level dependencies to be wrong ... implementation dependencies are another story.