Problem
So I'm making a video game and I'm facing a design problem. I would like to pass the reference of a class being constructed to a constructor of another object and pass this other new object to the super constructor of the first class.
Basically something like this:
class B extends A {
B() {
super(new C(this));
}
}
Context
So I have a World
class representing the world of my video game. This world can be played and displayed by a WorldScreen
. I don't want the World
to rely on any WorldScreen
. It would be bad design for a world to depend on a screen to be played, the world does not care what technology is used to render its entities and does not care about the UI too. So instead of having the world calling one of WorldScreen
's method when the player dies for example, we provide it a WorldEventHandler
(observer pattern but only one observer). That WorldEventHandler
will take care of keeping a reference to the screen to display the death screen when the player dies or the finish screen etc.
class World { //a video game world
//notifies about events going on in the world (e.g. the player's death)
final WorldEventHandler handler;
World(WorldEventHandler handler) {
this.handler = handler;
}
}
WorldScreen
is instantiating a specific WorldEventHandler
that will interact with itself.
class WorldScreen {
final World world;
WorldScreen() {
//all good, WorldEventHandlerImpl will interact with WorldScreen whenever needed (display death screen?)
world = new World(new WorldEventHandlerImpl(this));
}
}
This design is all perfect to me (still open for improvements), the World
is not dependant on anything but an interface to listen to its events and the WorldScreen
is able to customize its behavior with a specific implementation of that event handler.
The problem comes when I try to do inheritance with WorldScreen
. There's many different implementations of WorldScreen
that does slightly different things but still lots of things in common regrouped into the abstract WorldScreen
class.
abstract class WorldScreen {
final World world;
WorldScreen(WorldEventHandler handler) {
//fine too
world = new World(handler);
}
}
However, as you can see the WorldEventHandler
has to be specified by the subclass. It is up to the subclass to decide what to do with world events. So the error occurs when I try to instanciate a WorldEventHandler
with a reference to the screen in a subclass:
class OnlineWorldScreen extends WorldScreen {
OnlineWorldScreen() {
super(new OnlineWorldEventHandler(this)); //cannot reference 'this' before supertype constructor has been called
}
}
Workarounds
I've think about 2 workarounds but I hate both of them.
Setting the reference to the screen afterward with a set method:
- Breaks the model of all my
WorldEventHandler
for a constructor issue - Will do lot of dupplicated code since every implementation will require a set method with a different type to set.
- The field wasn't meant to be changed initially and I have no other reason to let other programmers think it might be a field that will get changed
- Breaks the model of all my
Creating an abstract
getEventHandler()
orbuildEventHandler()
inWorldScreen
to make the super constructor build it when creating the world.- What was supposed to be a constructor parameter is now a method
- That method is meant to be used only once and does basically nothing but a call to a constructor
- Makes the implementations of
WorldScreen
heavier
Question
Is there any better workarounds? If not, which is the best and why? If my design is flawed and could be changed into one without that issue, please tell me how instead of presenting a workaround.
Edit
To answer Sebastian Redl's comment, yes it makes sense for the screen to create the world. A screen is the current state of the game, typical examples would be MainMenuScreen, SettingsScreen, LoginScreen etc. So when you go from the MainMenuScreen to the OnlinePlayScreen, it creates the world and play it from your input. It does not make sense to have multiple screens on a single world since it's impossible to have multiple screens at once in the application (using LibGDX framework). The reason I want the World to be 100% standalone is to be able to run one on a server to check if a player is cheating or not. (Taking his inputs and checking if he reaches the same time on server that his client pretended to).
I could make a list of observers instead (not that I need to) but If I would do so, I would make a special implementation of WorldEventHandler
that can receive multiple listeners. It's way easier for the World
(that is already full with physic engine and game logic) to call a method from an object than looping into a list of 1 elements everytime.
WorldScreen
creating the world is very suspicious in the first place. Shouldn't it be possible to have multiple screens displaying the same world? Also, why make the event handler a constructor dependency and thus force exactly one handler? Why not add handlers to the world afterwards and allow multiple handlers?