views:

103

answers:

2

Here is the problem, lets say we are making a video game and want to use Dependency Injection. Here is what we have:

Game Class  // This is just the code to keep track of the overall game logic
Character Class // This would be the guys in the game, good and bad guys both
Weapon Class // The weapons for the characters

So normally when I do Dependency Injection I would inject the current location on the maps, and game state into the character so my character would have the info to know where to create itself, etc. Then I have the character create the weapon and inject the values as to the strength of the weapons, as well as some other general game state from the Game Class etc.

This almost seems like an anti-pattern to me. I say that because now you have (at least it seems so to me) code that is very brittle and hard to change. If we want to change the game state information that is passed we are forced to change all three classes. We make the original change to the Game class, then modify Character and then finally modify the Weapon class as well. That is a lot of work especially if you are going 5 levels deep rather than just the 3 here. Though yes it would allow for easier Unit Tests than no DI.

This again sounds like bad practice. Is this the way things are typically done? What is we sort of had a 'MotherShip' pattern where everything is at the top level. So instead of game creates character creates weapon we let game (or some other class) create all of them.

This way if we wanted to add a new weapon to a character the game class could just create the weapon itself and inject it. Not sure what to do on this one. Thanks

+1  A: 

Design questions are tough to answer, especially when the example doesn't seem to make sense. In this case, it makes not sense that a Character would create a Weapon. A character should be responsible for that one character. Maybe you can add a weapon to a character, but, unless the character is a weapons maker, I don't think it would actually create a new Weapon class.

BTW, I think a better pattern than either one of these would be the Factory pattern. Create a class who is responsible for creating weapons. And a class which is responsible for creating characters. That way, if there are 3 or 4 places which need to be changed when a character is created, that factory can handle that behavior and it is contained for future changes.

tster
I think the design question might not make sense to you because you maybe already know a proper way of doing it? That's just a guess. I think I'm still stuck in the old school OO thinking where each class owns lots of sub classes (like a world has houses, houses people, people have clothes etc). Your advice makes sense to me though. A Character I would think would have to have knowledge of his weapon though but that could just be injected.Thanks for the tip on the factory pattern. The case that I'm usually faced with would just be a single instance though. This example was the best I had.
John Baker
The thing you have to be careful of is paying attention to where the objects are actually created. When you use the "new" keyword you are locking yourself in to a single implementation, so you need to have that controlled. Furthermore, whoever creates an object is responsible for it until they can pass it to someone else who is responsible for it. The in {House, Person, Clothes} example, objects of the type Clothes should be created somewhere else and given to the Person or House object.
tster
Right okay, so that was my problem. I had the dependency backwards. I wrote a similar question on SO the other day and a number of people thought that dependency chain was perfectly normal, so I assume this isn't really known to everyone. Is there any principle or book that you are aware of that really deals with the proper dependency order and important practices such as these?Thanks
John Baker
+1  A: 

Chaining or nesting dependencies is a perfectly natural practice (although I have to agree with tster that your example sound a bit strange), but I think I can understand why you find it brittle - that is, if you inject concrete types into their consumers.

The trick is to introduce an interface at every level of dependency so that you can vary implementation independently of the consumers. As an example you should define an IGame interface and inject it into the Character class instead of the Game class itself.

Even so, interfaces with a lot of deep nesting can still be brittle because you might need to change the interfaces themselves too often. This is best addressed by striving to conform to the Hollywood Principle and Law of Demeter as much as possible.

Mark Seemann