views:

260

answers:

5

Imagine the typical type of application where you have a list of items with different properties. E.g. a tree-view with 100 items, each having a name, a rating, a rank-within-the-hottest-items-on-the-planet etc. Probably there are also many-to-many relationships between items and item-catalogs, or between items and item-creators etc etc.

Now this application naturally needs a filtering system. E.g. where I can construct complex filters with multiple conditions of all kinds, between data in different relationships.

The design task of writing such a filtering feature ought to be something MANY developers have done and there surely must be some kind of design pattern which is the most suitable for the task.

Anyone?

Edit: Switched to community wiki since I suspect there isn't any industry de factor pattern used for this. Question too generally formulated I guess.

A: 

If these relationships are expressible as RDF and OWL you can use a tool with a SPARQL endpoint (such as Jena) or a reasoner such as Pellet. But without more details it is not clear that this is the best approach.

peter.murray.rust
+1  A: 

I don't know about a design pattern for it, but you can look at some of the approaches that have been made for sorting, and it would be helpful if you explained some of them and why you didn't like them as an example.

For example, LINQ has a nice way to do sorting, using the Expression trees.

You can also look at sorting done in functional languages, where you can pass in the function to actually do the sorting, rather than hard-coding any particular sort.

If you were working in something like javascript then the sort function could be created on the fly.

James Black
The strategy pattern may be a good one to look at, as a starting point.
James Black
+1  A: 

Your looking for a relational database, from which you can use SQL. You can stand up a full one and connect to it from your application, or you can do something in between a full database and straight objects. In Java, for example, you could use an in-memory database like HSQLDB / JavaDB and use the featuers of that. You could also use JoSQL which will let you operate in SQL directly on your objects without the database at all.

Alternatively, if you wanted to program the thing yourself, you would start by keeping 2 copies of your data. One is your full set of data, the other is your view of the data after filtering. Then, you would create an index on your data for each column, by sorting the data and keeping its position in the sorted list. The same setup works for a filter match. If something matches a filter for a column, give it a 1, or 0 if not. Then when somebody switches the sort order you copy your data from the full list into the view list, or when the change the filter information, you would only take the data that had a match.

John Ellinwood
I like the idea of using SQL expressions as base for filter mechanics. Otherwise I feel this approach would forbid me to abstract the database as an anonymous and interchangeable storage layer. Correct me if I'm wrong.
sharkin
+1  A: 

I like the filter with predicate of Google Collections and I would implement something very similar if I couldn't use it. You may want to check this answer to a similar question for a implementation example. The implementation is in Java but, well, you'll see the pattern.

Pascal Thivent
Very interesting. That seems like a form of strategy pattern, also pointed out by James Black.
sharkin
+1  A: 

It's a bit difficult to actually point out what you want, so I'll take my own assumptions.

  1. The underlying collection should be unchanged after the filtering
  2. The result is not persistent

A classic approach is the use of views. This is basically lazy programming, where you create an object which can access the original collection and knows the filter to apply but will not make any computation as long as nothing is required.

On collections, the views are often implemented with iterators, and for the filtering, of course a Strategy Pattern as already pointed out.

For example:

Collection myCollection;
Predicate myFilter;

// Nothing is computed here
View<Predicate> myView(myCollection, myFilter);

// We iterate until we find the first item in the collection that satisfies
// the Predicate, and no more, to initialize `begin`
View<Predicate>::Iterator begin = myView.begin(), end = myView.end();

The net advantage is that if you (say) only need the 10 first items, then you'll only apply the predicate as much as necessary to find those 10 first, and no more.

Also, there is no copy of the elements involved, and your view is guaranteed to be updated even if you modify myCollection, although this may affect the validity of the iterators (as usual).

The problem is that (unless you implement caching), the result is computed each time.

If you want a more persistent result, then you'd better build a new collection containing only the filtered items (or references to them). There is no general pattern here for it depends on how you want to use the 'filtered' list.

As for the Strategy Pattern suggested, you can usually build your filter by block using the Composite Pattern and then pass the object thus built as the strategy.

The Composite Pattern is especially suited to represent the result of a parsed expression for example, you might want to have a look at expressions trees to get an idea.

Matthieu M.
I really like the thought of combining Composite and Strategy pattern, thanks!
sharkin