I think the idea of sub-classing makes more sense when you're talking about a QueryParser. The parser includes, mainly, two logics - parsing a query into query "segments" or "nodes" and then creating the appropriate Lucene Query instance for each sengment/node.
By modifying QueryParser so that it uses protected callback methods for creating the appropriate Query instance for different node types, you get a very clean and elegant query parsing solution.
All sub-classes can share the same parsing rules (which generally don't change), and just instantiating their own TermQuery or PrefixQuery instances.
Wouldn't you need to do that anyway with the Query factory? I mean, what if I want to create all the query types like the default implementation, but change the PrefixQuery instance to something I wrote? Wouldn't I need to extend the default query factory? Sounds exactly like extending QueryParser to me.
I recently implemented a query parser for a different query syntax than Lucene's, but I still wanted to create Lucene Query objects. The parser includes different protected callback methods like getTermQuery, getPhraseQuery, getPrefixQuery etc, providing a default implementation to each of course. It parses the query into "nodes" and then invoke the appropriate callback method per node (i.e., for a phrase node, it invokes getPhraseQuery).
We have several sub-classes which extend this parser to provide their own implementation for various node types (for example, this approach allows you to remove any "prefix" or "wildcard" nodes from the query, without touching the parser).