A tri-state filter allows for flexible configuration of
multi-phase filtering. It effectively allows a conditional behavior
for filtering logic that can answer "yes", "no",
and "I don't know."
This can also be used to build classic bi-state filtering, such as
filters that use a boolean predicate to say "keep" or "discard." Where the
tri-state filtering pattern shines, however, is in the ability to combine
different filtering rules to build a sophisticated filter at run-time
that bi-state filtering would prevent.
In contrast to the bi-state filter, the default policy that is applied when
not matching an item with the predicate is to simply ignore it.
This means that in order to implement both matching and discarding
policies like a bi-state filter, you must do one of the following:
- Implement a default policy that overrides the "Ignore" action.
- Use both "keep" and "discard" predicates together in sequence.
The two techniques above are not mutually exclusive. In practice, tri-state
filters are used to build up chains of filters which can delegate down
the chain if up-stream filters do not have enough information to make
a keep or discard determination. Even in chained filters will have a
default policy that will override the "ignore" outcome.
Filter chains that
have a default "exclude" policy that overrides "ignore" policies are
called "exclusive" filters. Their counterparts are "inclusive" filters.
In other words, Exclusive tri-state filters include an element if and only
if there was a matching include rule before any matching exclude rules
or the end of the filter chain.
Inclusive tri-state filters exclude an element if and only if there was
a matching exclude rule before any matching include rules or the end of
the filter chain.