Blocking calls and UIs IV
In the previous post we solved the computer vs computer
usage. Let’s face the interleaving of computer
and human
in this one.
With only humans
we had the following API:
And with only computers
we had the following:
We need to support both ways of usage in a generic way. Let’s start by describing what they do and find the things they have in common.
We are calling both move
methods to advance to the next player. But, for a human
the game requires a location
to play. If we keep the location
parameter, what do we send when the computer is playing? nil
?. And more importantly, how do we know the computer is playing to send nil
? Do we need to add the current_player
method to Game
? That will make the UIs know and duplicate some of the Game
logic and violates the single responsibility principle.
We have another option, we can keep the move
method without any parameters and provide that location in some other way. But in what way? If the Game
knows when it needs the location
value, makes sense for the Game
to request it when is needed. What object should Game
request for the location
? The location
comes from the user through the UI, but the Game
shouldn’t know about any specific UI. We need to use the dependency inversion principle here: Game
depends on an abstraction to get the location
and the specific UI will provide its implementation for it.
We have to keep in mind that in a Gui
, if the Game
asks to get_location
, the user may not have selected a location
yet. And we cannot block for the same reasons we talked about in the previous post. That means that the object that provides the location
could not be ready to be queried.
An implementation could be:
In the Cli
things are much easier. We know that each time we ask_to_select_location
it will block and return a valid location
. The implementation could be as simple as:
With that, we can have all modes working.