Dependency Injection – Inversion of Control

It was time for the second article (but it melancholy sounded πŸ™‚ ) in the previous article, we refactored the code of the web game prototype, and so on there you can still improve a lot, using mainly dependency injection what exactly in this article we will do, go πŸ™‚


Introduction

We already have the code of this game somewhat orderly and specific functionalities drawn for separate classes.

Before we go to the article, I would like to clarify the issues of character classes. One of the readers mentioned that the character classes are unnecessary, that it is better to do the functions because these classes only change their state and do not have a separate logic, he is right. However, it would be harder to understand and I am not doing a commercial game that will be kept for years, I just want it to be easy to understand, sometimes you have to take my point of view πŸ™‚

However, if we were to do some more complicated example of the game and each of the classes would have separate functions for a particular character class, the functions of the case would not do it because it would be a separate logic. Well, everything is good, really, if it will fit the problem πŸ™‚

If you are going to do a big game in the future, let’s assume an RPG and the character classes will only change their state and have no separate logic, it’s better to do functions than classes, but if for example the barbarian class will have some special skills such as:

And let’s assume the mage class will look like this:

In this case, I would stay in the classes, for easier maintenance, modification, testing etc, etc πŸ™‚

And back to the article … πŸ™‚

We have to limit the use of the word “new” as much as possible in the application code. It will also show how to apply dependency injection, if someone creates projects in TDD.

And it will show how to use only abstract types and not specific ones when the class needs some dependencies from other classes as well as the CharacterSkillPoints class from the previous article.

You should not and you can not even place the types of specific classes and other classes.

Okay, but here is another snag, as I said at the beginning we must avoid the word “new” in the application and create instances in the constructor what we should not do …

And now someone can think “Well, but how get it around? Somehow I have to create objects!”

Easy there is the way πŸ™‚

Well, to fight!

If I want to show some code from the previous example, it will paste the link to this code on github, so that it does not collapse the article with the wall of the code πŸ™‚


Interfaces in Dependency Injection

Character classes are unchanged, let’s start with validating classes login and password.

The classes for validating the login and password from the previous example looked like this:

Login validation class: https://github.com/Slaw145/Dependency-injection–refactored-game-project/blob/master/RefactoredGameProject/LoginValidator.cs

Password validation class: https://github.com/Slaw145/Dependency-injection–refactored-game-project/blob/master/RefactoredGameProject/PasswordValidator.cs

And now they look like this:

LoginValidator class

And the PasswordValidator class

The change in the code is small, we only added interfaces, but what are the interfaces for?

Interfaces give a lot of things, mainly two the most important things.

First of all, instead of making the class dependent on specific types, we will be able to make it dependent on abstraction, which is the correct way, such as the GameServer class, we addicted in the previous article from specific types, and the correct dependence on abstraction looks like this:

Now it’s enough that in place of the specific type classes we put interfaces and the matter dealt with, but we will go to the GameServer class later, then in the article will show the entire GameServer class code πŸ™‚ but everything in turn πŸ™‚

Secondly, thanks to the interfaces, we can test our application without running it, which is very important for me as well as for programmers who use TDD. What will I show immediately on the example πŸ™‚


Mocking interfaces

Let’s assume that we do not have implemented the LoginValidator class and only we have its interface and we want to implement tests and not run the application in such a case, thanks to the interfaces we can mock this class, as below.

And in this way, we can test the interface without having it implemented in the production code.

Thanks to the interfaces, you can also mock class when you do not care about on some level details on the validation of login or password, but it will show later in the article, I do not want to mix, I want everything to be understandable and orderly.

In unit tests for validating classes login and password, we changed only the specific type of LoginValidator and PasswordValidator classes to their interfaces at the end of the article as usual, I put a link to github with all source code, so you can see everything πŸ™‚


Other classes with DI

Let’s move to the CharacterSkillPoints class

In the previous article it looked like this: https://github.com/Slaw145/Dependency-injection–refactored-game-project/blob/master/RefactoredGameProject/CharacterSkillPoints.cs

It does not look very encouraging … the user creates only one class and we have created all classes “just in case” and methods for each class, we have to improve this …

And now it looks like this:

It already looks 100 times better we create only the necessary character class and pass it to the method that gives away the skill points for this class, bomb πŸ™‚

Let’s see how this class tests from the previous article looked like:

Before changes:
https://github.com/Slaw145/Dependency-injection–refactored-game-project/blob/master/NUnitTestGameProject/CharacterSkillPointsTest.cs

After changes:

It also looks like a lot better, we do not have so many tests now and we’re just testing the class we’ve created in the game.

Let’s see what the main GameServer class looks like, which manages all of these classes to validate customer data and character classes

First, let’s look at the top of the constructor so we just got rid of the new from the application code and changed the concrete class types to their interfaces. πŸ™‚ A objects of these classes are created in the client. This is how the correct creation of objects looks like.

However, this constructor can be further improved. Let’s assume that we would have 10 dependencies, in which case this constructor would not be readable at all, but we will also deal with this in the next article. Let’s move on.

The RegisterUser() method calls the methods responsible for the validation of the login and password, then we check whether both methods returned true, if they do, return true, if not, we return false. And we display an exception in the client. Here we return the truth or false so that this method can be easily tested.

Let’s move to the CreateCharacter() method, we now have only one line that passes the created character class to the CharacterSkillPoints class. In the previous article we had something like this in this method:

So you do not have to play in any patterns πŸ™‚ I said that dependency injection makes life easier πŸ™‚

In the last method, StartGame() we check if the user logged in correctly and created the character.

Let’s see only what GameServer class integrations tests look like, ie tests that check if all classes are working with each other and this is what the StartGame() method is very useful for. πŸ™‚

Here you are πŸ™‚

With the help of the StartGame() method, we check all the cases that could go wrong at the start of the game. We test those cases in which the game crashes and the ones in which the game starts. Well, even rhyme πŸ™‚

Let’s see if all tests pass.

And now let’s assume that on this level of abstraction we do not care about the details of creating a character, so we have to mock a character classπŸ™‚ Just mock the interface ICharacter

And we will provide a mock interface to the StartGame() method πŸ™‚

And we do not need the CreateCharacter() method anymore

As I said, the link to the entire code as usual will be in the summary, you can entertain with it πŸ™‚

Let’s check again if the tests pass πŸ™‚

Let’s see the client, ie the WebServer class. In it, we simply use all the classes we have created, log in here, create a character class, and enable the game.

Functions that log the user, creating a character class and starting the game, I have separated into separate methods and all messages are in the client not in the game code as it should be.

Result:

This image has an empty alt attribute; its file name is resultgameserver.png

Testing unimplemented interface – problems

Well, I showed you how to test the ILoginValidator interface not yet implemented, but it was just a demonstration to show what’s going on, because we have this interface implemented, so let’s assume that we want to add ICharacterRace interface to expand the game by race, or elf , dwarf, halfling, etc., but we do not want to run anything but implement the tests, not the interface because it’s boring πŸ™‚

Let’s see what the ICharacterRace interface looks like

Let’s assume that this method have to return the created race of characters. Let’s add the appropriate code in the GameServer class for this interface.

In the constructor:

And the method that calls the ICharacterRace interface method.

And in the client.

But what is it now in the GameServer constructor? You can not create an interface instance! What a man … It will not even compile. I can only mock this interface.

But since it will not compile, we will not create GameServer class, so we will not run any tests. And what now? Should we spread our hands and cry?

Calmly πŸ™‚ as in IT it is mainly about solving problems and in the next article we will solve this problem, we will also solve the problem of constructors with a lot of dependencies and we will remove new even from the client’s level.


Summary

In the next article we will go to the so-called containers, which will solve our problems, which I described above πŸ™‚

Link to github with the whole code from this article: https://github.com/Slaw145/DependencyInjectionInversionOfControl

This content also you can find on medium:  https://medium.com/@sawomirkowalski/dependency-injection-inversion-of-control-4edf8d1fdcad

As a standard, I remind you about the newsletter, which I send notifications about new entries and additional information about the IT world in general.

And NECESSERILY join the DevmanCommunity community on fb, part of the community is in one place 

– site on fb: Devman.pl-Slawomir Kowalski

– group on fb: DevmanCommunity

Ask, comment underneath at the end of the post, share it, rate it, whatever you want. πŸ™‚

 
If that post was useful for you share it with your friends :)

Post a comment

avatar
  Subscribe  
Notify about