This article examines extending Java Enum
s used as property values
within JavaBeans combined with the Java Stream API to create and extend
fluent interfaces. From
Wikipedia:
The Java Stream API provides the method chaining; this article will examine
how Java Enum
s may be extended (specifically to implement
Predicate
to contribute to a fluent interface’s quality of
being similar to “written prose.” For example:
will allow support for fluent expressions like:
Complete javadoc is provided.
Extending Enums
Enum
values are constants but they are also subclasses of Enum
and those subclass implementations may have custom fields and methods. For
example, java.time.DayOfWeek
implements the
TemporalAccessor
and
TemporalAdjuster
interfaces so DayOfWeek
provides
implementation methods for those interface methods. The Suit
implementation demonstrates how subclass fields may be defined and set by
defining a custom constructor.
Implementing Predicate
The key to contributing to the fluent interface provided by
Stream
is for the Enum
subclass to implement
Predicate
. Of course, that Predicate
must test the bean
that the Enum
is a property for. For example, Rank
and
Suit
must test Card
:
Note: Both implementations provide static is
methods to further contribute
to the “fluency” of the API.
To re-inforce the fact that Rank
and Suit
are
bean properties of Card
, Rank
and Suit
are implemented as
inner classes of Card
.
Fluent Implementation - Poker Hand Ranking
To demonstrate the “fluency” of the API, a Poker Ranking
Enum
may be defined.
To complete the Poker “domain specific language” the Rank
and
Suit
types must provide static Predicate
SAME
fields,
Rank
must provide a static SEQUENCE
Predicate
,
and Ranking
must provide static with
and holding
methods:
The Ranking
Predicate
Enum
combined
with the Combinations
Stream
introduced in
this article may be
used to test for a specific Poker hand.
While this implementation is complete, the Combinations
Stream
provides an of(int,int,Predicate<List<T>>,Collection<T>)
method that
allows the specification of a Predicate
that when it
evaluates to false
will stop iterating over that branch. The
Ranking
Enum
may be extended to provide that
Predicate
by providing a possible()
method:
which in combination with the
Combinations.of(int,int,Predicate<List<T>>,Collection<T>)
method will
optimize the search for ThreeOfAKind
by escaping a branch if the first
Card
s are not the same Rank
, Straight
if the
first Card
s are not a sequence, etc.
The logic in Ranking.find(Collection<Card>)
and Evaluator
demonstrate more sophisticated logic.
Summary
Implementing Predicate(BEAN)
for BEAN
property types
(including Enum
) will contribute to making an API “fluent” when
used in combination with Stream
.