Java Reference
In-Depth Information
}
private
private
void
void
messageBob
(
NetSocket richard
) {
withConnection
(
messageBobWithConnection
(
richard
));
}
private
private
Handler
<
NetSocket
>
messageBobWithConnection
(
NetSocket richard
) {
return
return
bob
-> {
checkRichardMessagedYou
(
bob
);
bob
.
write
(
"bob\n"
);
vertx
.
setTimer
(
6
,
id
->
richard
.
write
(
"bob<hai"
));
};
}
private
private
void
void
checkRichardMessagedYou
(
NetSocket bob
) {
bob
.
dataHandler
(
data
-> {
assertEquals
(
"richard>hai"
,
data
.
toString
());
bob
.
write
(
"richard<oh its you!"
);
});
}
private
private
void
void
checkBobReplies
(
NetSocket richard
) {
richard
.
dataHandler
(
data
-> {
assertEquals
(
"bob>oh its you!"
,
data
.
toString
());
moduleTestComplete
();
});
}
The aggressive refactoring in
Example 9-8
has solved the pyramid of doom problem, but at
the expense of splitting up the logic of the single test into several methods. Instead of one
method having a single responsibility, we have several sharing a responsibility between
them! Our code is still hard to read, just for a different reason.
The more operations you want to chain or compose, the worse this problem gets. We need a
better solution.
Futures
Another option when trying to build up complex sequences of concurrent operations is to use
what's known as a
Future
. A
Future
is an IOU for a value. Instead of a method returning a
value, it returns the
Future
. The
Future
doesn't have the value when it's first created, but it
can be exchanged for the value later on, like an IOU.