I am creating a custom query class, and i am unsure about the most elegant way to code it.
The goals are:
- Easy to use
- Extensibility
- Flexible so that complex queries can be formulated
Approaches
Currently i can think of two alternatives.
1. Builder pattern
Result r = new Query().is("tall").capableOf("basketball").name("michael").build();
The methods is()
, capableOf()
and name()
return a self-reference to the Query
object. build()
will return a Result
object.
2. Static Imports
Result r = new Query(is("tall"), capableOf("basketball"), name("michael"));
The methods is()
, capableOf()
and name()
are static imports and return Condition
objects. The Query constructor takes an arbitrary number of conditions and returns the result.
And/Or/Not queries
More complex queries like the following are complicated to formulate:
tall basketball player named [michael OR dennis]
UNION
silver spoon which is bent and shiny
Builder pattern:
Result r = new Query().is("tall").capableOf("basketball").or(new Query().name("michael"), new Query().name("dennis")).
union(
new Query().color("silver").a("spoon").is("bent").is("shiny")
).
build();
This is difficult to write and read. Also, i do not like the multiple use of new
.
Static imports:
Result r = new Query(is("tall"), capableOf("basketball"), or(name("michael"), name("dennis"))).
union(color("silver"), a("spoon"), is("bent"), is("shiny"));
Looks better to me, but i do not really like the use of static imports. They are difficult in terms of ide integration, auto-completion and documentation.
Sum up
I am looking for an effective solution, therefore i am open to suggestions of any kind. I am not limited to the two alternatives i presented, if there are other possibilities i'd be happy if you tell me. Please inform me if you need further information.