Skip to main content

The Finder Pattern

Posted by fabriziogiudici on January 15, 2010 at 3:24 AM PST

In many previous code examples in this blog I've used the “Finder pattern”, that I've elected as one of my best practices (it's standard in all my new APIs and will be retrofitted to the old ones). Before moving on with more examples, I think it's high time I shortly introduced it formally.

As the name suggests, it helps whenever you need to provide a search of some type. For instance, in the Hierarchy API the interfaces HView and HItem (name shortened from Hierarchical*** in my previous post) implement a Composite pattern, so a HItem has got children:

public interface HView

  {  

    @Nonnull

    public Finder<HItem> findChildren();

    

    @Nonnull

    public Builder<HItem> createChild();

    

    @Nonnull

    public Builder<HItem> findOrCreateChild();

  }



public interface HItem extends HView

  {

    @Nonnull

    public HView getView();



    @Nonnull

    public HItem getParent()

      throws NotFoundException;

  }

There are many ways to search for children; for instance, you could search for a specific child with an id, or if you recall that any object in the Hierarchical API is logically bound to another object, you could explicitly search for children with a specific binding. Thus, one might need to have methods such as findChildren(), findChildById(), findChildrenBoundTo() etc. This is not a scalable approach in the perspective of flexibility, as any extension of the search facility would need the introduction of a new method. Instead, all of the above can be done with the single findChildren() returning a Finder:

HItem parent = ...;

List<? extends HItem> allChildren = parent.findChildren().results();

specificChild = parent.findChilren().withId("xyz").result();

List<? extends HItem> childrenBoundToAPhoto = parent.findChildren().boundTo(Photo.class).results();

Ok, you're probably saying that now new methods must be added to the Finder - right, I'll give more details about how to extend a Finder in another post, but in the meantime the problem has been restricted to extending a single class, instead of the many that support queries; moreover, the fact that the search responsibility is given to a specific class makes it possible to add common features without duplicating code.

For instance, if you want to retrieve only a subset of the results (usefulr for instance with the paginated views), you can specify it:

HItem parent = ...;

List<? extends HItem> someChildren = parent.findChildren().from(10).max(20).results();

HItem the7thChildren = parent.findChildren().from(7).firstResult();

List<? extends HItem> childrenBoundToAPhoto = parent.findChildren().boundTo(Photo.class).from(10).max(30)..results();

It is possible to use a Finder just to know the number of the items that would be produced by the query:

HItem parent = ...;

int howManyChildren = parent.findChildren().count();

int howManyChildrenBoundToAPhoto = parent.findChildren().boundTo(Photo.class).count();

Depending of the implementation, asking for a count of items could generate an optimized query (e.g. a thing such as select count(*) where available). Right, because the fact that the responsibility of searching stuff is delegated to a specific class (or set of classes, as Finder acts often as a Façade pattern) makes it possible to decouple the implementation - which in a component scenario might even be pluggable, that is capable of extending functionalities by adding plugins to the system.

The fact that a Finder represents all the needed information for performing a query, but not the results of the query itself, makes it possible also to serialize it for a later retrieval (and execution), a useful feature for saved queries and such.

So, basically the Finder is a class implementing the Fluent interface pattern for specifying all the information needed to create a query (in fact you find basically the same pattern e.g. in the JPA API for creating JPAQL queries).

Related Topics >>

Comments

Order of fluent finder method calls

In your implementation, does the order of the finder methods matter? Suppose two of your finder methods are: Finder orderByDescription(boolean ascending); Finder orderByTitle(boolean ascending); Consider the following line: List<? extends HItem> someChildren = parent.findChildren().orderByDescription(true).orderByTitle(true).results(); This call would produce the SQL order-by clause "ORDER BY description ASC, title ASC". Now consider the same call, but with the two "orderBy" methods reversed: List<? extends HItem> someChildren = parent.findChildren().orderByTitle(true).orderByDescription(true).results(); This call would produce "ORDER BY title ASC, description ASC". The order in which the methods are called is important. Also, if these "orderBy" methods were mixed with from(int) and max(int), then the order in which they are called could affect the final results. Thanks, Glen Hein

Very good points. First, the

Very good points. First, the answer depends on the implementation; for instance, an implementation could just accumulate the properties and defer the creation of the query until results() is called (what I usually do). In this case you could call from() and max() in every moment and this would have the same result (the "cutting" is performed on the sorted results"); or - instead- one could decide to make them significant, which would change the behaviour as you say.

Of course it would be better to define a general rule and force implementations to stick to it. A strict approach to the problem would for instance suggest to implement a sort of a (simple) state machine to enforce some rule, as e.g. preventing the call of from() and max() to be called only after ordering, thus forcing only one interpretation. It also depends on the database you're using; for instance, with trivial SQL from() and max() always apply at the end, but perhaps one could create some nested queries - or perhaps not.

While enforcing some constraints in general simplifies the imlementation, I'm more open to a flexible solution. So far, in my code I have used mostly the "don't care option", while in a few specific points I'm trying the "care" thing. Implementing it is not complex, as you only need to keep a List of name=value pairs, rather than setting properties. My only doubt is that the "don't care" option allows to do a thing (that I've relied upon in at least one case): "overriding" values. For instance:

Finder<Foo> fBase = xx.findChildren().some().various().options();
Finder<Foo> f1 = fBase.from(0).max(10);
Finder<Foo> f2 = fBase.from(10).max(10);
Finder<Foo> f3 = f2.max(20);

and then you use them calling results() etc... That is, I'm using fBase to set some common properties, and f1, f2, f3 can specialize them. I have still to take a decision on that - I'm moving towards the idea that overriding properties gets too complex and probably I'll decide to adopt the "care" option. I also haven't figured out yet if it's more or less (or equally) easy to read a fluent Finder in the "care" or "don't care" mode. What do you think?
 

Thanks.

 

Very interesting. I hadn't

Very interesting. I hadn't considered the "overriding" case. I'm playing with the Finder Pattern in some proof-of-concept code and my fluent methods simply return their "this" value. So overriding wouldn't work as expected. For overriding to work, I would have to return a new finder with every call. That seems wasteful. I could create a "cloneFinder" method that returns a deep copy.

Another thing, in my code I have a User object with an identifier, first name and last name. Instead of having a withId, withFirstName and withLastName method, I created an enum called Field that contains ID, FIRST_NAME, and LAST_NAME. Then I created a withField method that takes a Field and a value.

Correct - in fact I did the

Correct - in fact I did the same (most Finders return this, and the different one clones - BTW, cloning is a bit of an annoyance for all the fields, and I use some reflection). I agree that for with() (and sortBy()) using an argument is a better option. BTW, are you aware of some reference about this stuff? Curiously, googling for "fluent finder pattern" you find stuff related to .NET, while searching for "java finder pattern"... now gets this very blog post! I suppose this pattern is more frequent with .NET because of LINQ?

http://russelleast.wordpress.com/2008/09/20/implementing-the-repository-...
http://www.davidhayden.com/blog/dave/archive/2007/09/19/ChainOfResponsib...
http://ayende.com/Blog/archive/2007/07/18/Fluent-Interfaces-amp-Method-C...
 

Thanks

Thanks Fabrizio for this explanation on this class. simulation