The antipattern-plagued game I'm creating is using ASP.NET Core, which, in many cases, requires the use of dependency injection. This is new and counter-intuitive to me. Up to now, I managed to limit the use of dependency injection to where it is strictly required by the framework, while writing the mechanics of the game in the "my" old way, that is, with a lot of explicit object creations (var blah = new SomeClass(arg1, arg2)
etc.) (And without creating interfaces when only one class would implement them.)
Reading a bit about dependency injection, which the framework's documentation recommeds to use everywhere, I was perplexed to find out that I should not call constructors nor explicitely create any objects, because instead, I should request all objects I would like ClassA
to ever create in the constructor of ClassA
and let the framework provide them for me!
Skimming over my code, in many cases I can't see how could I accomplish this. Simply moving all new
s to the constructor doesn't seem to work.
One example is when it seems to be runtime dependant on which objects should be created.
To be more specific, let me provide an example for this example ;P There are many Move
s characters can use:
public class Punch : Move
{
// ...
}
public class SwordSlash : Move
{
// ...
}
etc.
The client (web browser) will typically send the server a command with a name of the move the player would like to execute. Omitting the many necessary validations (for simplicity) this is the code of the relevant method of the server:
var moveType = System.Type.GetType("Game.Mechanics."+moveTypeName);
if (!(moveType.BaseType == typeof(Move))) return; // OK one of the many validations I did not omit
move = (Move)Activator.CreateInstance(moveType, args);
That's right - the server just looks if there is a class whose name is equivalent to the string sent by the client. Well, dependency injection violation?
So how should I do this instead?
The only way that comes to my mind is to have a class whose contructor will accept ALL (currently 79 and counting) moves and that will have a method with a gargantuan switch to select a proper move:
public class MoveSelector : IMoveSelector
{
private readonly IPunch punch;
private readonly ISwordSlash swordSlash;
// 77 more privates
public MoveSelector (
IPunch punch,
ISwordSlash swordSlash,
// 77 more args
) {
this.punch = punch;
this.swordSlash = swordSlash;
// 77 more assignments
}
public IMove SelectMove(string moveName)
{
switch(moveName)
{
case "Punch":
return punch;
case "SwordSlash":
return swordSlash;
// 77 more cases
}
}
}
I somehow feel this is not the right way to go. Especially since adding a new move would now get rather tedious.
So how should I fix my code so that I don't violate the rule that I'm supposed to avoid the new
keyword?
IMove
private?.return new whatever()
in each case. It's a classic example of a Factory Method pattern. You don't actually need any local variables to make it work, unless of course you feel like holding onto the resultingIMove
object locally.