It always amazes me how divided the opinions are on this topic. I’m going to try an answer the OP’s questions as objectively as possible without letting my personal opinion get in the way. I’ll try, I may fail.
When it comes to software design, anything can work, until it doesn’t. There’s no perfect design, but there are designs that can get you into trouble in certain situations.
Note: each design might have more than one problem but I’m just going to use one example for the sake of argument
Design 1: Passing the ContentManager to the entity
public Player(ContentManager contentManager)
{
_texture = contentManager.Load<Texture2D>("player");
}
The first problem I see with this design is that the data about which texture to load is coupled to the class. For example, what happens if you want to make a second player and use a different textures for each instance e.g. "player1"
and "player2"
.
There are a couple of solutions to this problem. You could pass in the texture name as a second parameter to the constructor but at this point you might as well just pass in the Texture2D
directly. An alternate solution is to create a Player1
and Player2
class but unfortunately this won’t scale very well when you’ve got 32 players in your game.
Design 2: Static ContentManager
public Player(string texture)
{
_texture = Game.MyContent.Load<Texture2D>(texture);
}
This design looks good on the surface. It appears to make your life easier because you’re only ever going to need one ContentManager
in your game, right? Until one day you find a reason that you actually want to have 2 content managers. For example, when your loading level 2 you’d like to be able to unload all the content from level 1 and load the content for the next level without having to think about it too much.
There might be a few ways around this but in my experience the singleton pattern will eventually come back to bite you. You’ll be in a world of pain the moment you realize that you actually need more than one instance of something you’ve previously assumed is a singleton.
Design 3: Pass Texture2D directly
public Player(Texture2D texture)
{
_texture = texture;
}
This design doesn’t have any of the previous problems. Constructor injection like this forces you to only inject the things you actually need to create an instance of that class. You can decide outside the Player
class if you want more than one player or use more than one content manger.
This is my preferred design out of the 3 but I’ll try to be objective about it. Constructor injection isn’t perfect. The main problem with this design is that your constructors tend to have a lot of parameters passed in as your object gets more complex. There are other designs that try to solve this problem (composition, IoC, etc) but they also come with their own set of pros and cons.
In terms of efficiency none of the above designs are going to be noticeably different. By far the slowest part of this type of code is calling Content.Load
. You’re going to have do to that in all cases and passing a few pointers around (weather it be Texture2D
, ContentManager
or looking up something from a Dictionary
) isn’t going to make a lick of a difference.