C# – Loose coupling and shuffling dependencies

cdependency-injectiondesign-patternsinterfaces

I have a bunch of classes that look something like this:

public class MyGame()
{
    private Graphics graphics;

    private Player player;

    public MyGame()
    {
        graphics = new Graphics();
        //...
    }

    protected void Initialize()
    {
        player = new Player();
        //...
    }

    protected void Update()
    {
        player.DoStuff();
        //...
    }

I've been reading about design patterns, and I've come to understand that this is not a very good design because it isn't loosely coupled. Instead of coding to interfaces, I'm coding to implementations (Graphics, Player, etc.).

In order to fix this perceived problem, I start by changing those dependencies to interfaces:

public class MyGame()
{
    private IGraphics graphics;

    private IPlayer player;

    public MyGame()
    {
        graphics = new Graphics();
        //...
    }

    protected void Initialize()
    {
        player = new Player();
        //...
    }

I'm not sure how helpful that really is, but it's nice that the graphics field (for example) isn't tied to the Graphics class – I can use the AwesomeGraphics class or SparklyGraphics class instead as long as those classes implement IGraphics.

But I still have hard dependencies on Graphics and Player, so what was the point of all that refactoring? (My actual code is much more complicated.) I've also come to understand that dependency injection is a good idea, so that's what I try to do next:

public class MyGame()
{
    private IGraphics graphics;

    private IPlayer player;

    public MyGame( IGraphics graphics, IPlayer player )
    {
        this.graphics = graphics;
        this.player = player;
        //...
    }

This looks really nice because I no longer have any hard dependencies in MyGame. However, the dependencies are still in my code – they've just been moved to the class that instantiates MyGame:

static class Program
{
    static void Main( string[] args )
    {
        using ( var game = new Game( new Graphics(), new Player() )
        {
            game.Run();
        }
    }
}

Now I'm back where I started! This class is not loosely coupled at all! So, again, what was the point of all that refactoring? I'm pretty sure I could use an IoC container to take care of these dependencies somehow, but that would likely just add a ton of complication to an already complicated project. Plus, wouldn't that just be moving those dependencies once again to another class?

Should I stick with what I had in the first place, or is there some tangible benefit that I'm not seeing yet?

Best Answer

You have gained the benefits of loose coupling in your refactoring. You've moved the knowledge of the precise implementation outside of your MyGame class and into a higher-level class. This is good: by keeping all knowledge of what the precise implementations are together, you're improving the structure of your code, making it easier for high level changes to take place, and making it easier to make changes that involve, for example, using multiple implementations of your Player class (perhaps by introducing a NetworkPlayer or AIPlayer later). MyGame now has one fewer reason to change, so is closer to having a single responsibility, and the Single Responsibility Principle is now considered one of the most important in object-oriented design by many programmers.

Related Topic