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:

namespace Dependency_Injection___Inversion_of_Control
{
public class Barbarian : ICharacter
{
// some variables strength, stamina itd
        public void CriticalHit()
{ }
        public void DragonStrength()
{ }
        public void Regeneration()
{ }
        public void AxeMaster()
{ }
}
}

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

namespace Dependency_Injection___Inversion_of_Control
{
public class Mage : ICharacter
{
// some variables strength, stamina itd
        public void IceBolt()
{ }
        public void SummonOrc()
{ }
        public void FireBall()
{ }
        public void Prayer()
{ }
}
}

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.

namespace RefactoredGameProject
{
public class CharacterSkillPoints
{
public Paladin paladin;
public Barbarian barbarian;
public Mage mage;
public Thief thief;
        public CharacterSkillPoints()
{
paladin = new Paladin();
barbarian = new Barbarian();
mage = new Mage();
thief = new Thief();
}
        // other methods
}
}

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

namespace Dependency_Injection___Inversion_of_Control
{
public interface ILoginValidator
{
bool LoginValidate(string login);
}
    public class LoginValidator: ILoginValidator
{
string LoginPattern = @"(?=.*[A-Za-z0-9]$)[A-Za-z][A-Za-z\d.-]{0,19}";
        public bool LoginValidate(string login)
{
Match loginmatchresult = Regex.Match(login, LoginPattern);
            if (loginmatchresult.Success)
{
return true;
}
else
{
return false;
}
}
}
}

And the PasswordValidator class

namespace Dependency_Injection___Inversion_of_Control
{
public interface IPasswordValidator
{
bool PasswordValidate(string password);
}
    public class PasswordValidator: IPasswordValidator
{
string PasswordPattern = @"(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}";
        public bool PasswordValidate(string password)
{
Match passwordmatchresult = Regex.Match(password, PasswordPattern);
            if (passwordmatchresult.Success)
{
return true;
}
else
{
return false;
}
}
}
}

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:

namespace RefactoredGameProject
{
public class GameServer
{
ILoginValidator loginvalidator;
IPasswordValidator passwordvalidator;
public ICharacterSkillPoints characterskillpoints;
       // other methods
}
}

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.

namespace DependencyInjectionTests
{
[TestFixture]
class MockLoginValidatorTest
{
[Test]
public void test_if_login_is_valid()
{
var mock= new Mock<ILoginValidator>();
            mock.Setup(x => x.LoginValidate("assd12")).Returns(() => true);
            bool ifloginvalid = mock.Object.LoginValidate("assd12");
            Assert.IsTrue(ifloginvalid);
}
[Test]
public void test_if_login_is_not_valid()
{
var mock = new Mock<ILoginValidator>();
            mock.Setup(x => x.LoginValidate("adasd123@")).Returns(() => false);
            bool ifloginnotvalid =   mock.Object.LoginValidate("asdasd123@");
           Assert.IsFalse(ifloginnotvalid);
}
}
}

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:

namespace Dependency_Injection___Inversion_of_Control
{
public interface ICharacterSkillPoints
{
ICharacter CreateCharacter(ICharacter character);
ICharacter GiveOutSkillPoints(ICharacter character);
}
    public class CharacterSkillPoints: ICharacterSkillPoints
{
public ICharacter CreateCharacter(ICharacter character)
{
return GiveOutSkillPoints(character);
}
        public ICharacter GiveOutSkillPoints(ICharacter character)
{
character.Strength += character.AdditionalStrength;
character.Stamina += character.AdditionalStamina;
            return character;
}
}
}

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:

namespace Tests
{
[TestFixture]
public class CharacterSkillPointsTest
{
ICharacter character;
ICharacterSkillPoints characterskillpoints;
        [SetUp]
public void TestSetup()
{
characterskillpoints = new CharacterSkillPoints();
            CreateCharacter();
}
        void CreateCharacter()
{
character = characterskillpoints.CreateCharacter(new Paladin());
}
        [Test]
public void check_skill_points_strength()
{
int StrengthSkillPoints = character.Strength;
            Assert.AreEqual(26, StrengthSkillPoints);
}
        [Test]
public void check_skill_points_stamina()
{
int StrengthSkillPoints = character.Stamina;
            Assert.AreEqual(22, StrengthSkillPoints);
}
}
}

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

namespace Dependency_Injection___Inversion_of_Control
{
public class GameServer
{
ILoginValidator loginvalidator;
IPasswordValidator passwordvalidator;
ICharacterSkillPoints characterskillpoints;
        public GameServer(ILoginValidator loginvalidator, IPasswordValidator passwordvalidator, ICharacterSkillPoints characterskillpoints)
{
this.loginvalidator = loginvalidator;
this.passwordvalidator = passwordvalidator;
this.characterskillpoints = characterskillpoints;
}
        public bool RegisterUser(string login, string password)
{
bool ifloginvalidate = loginvalidator.LoginValidate(login);
bool ifpasswordvalidate = passwordvalidator.PasswordValidate(password);
            if (ifloginvalidate == true && ifpasswordvalidate == true)
{
return true;
}
else
{
return false;
}
}
        public ICharacter CreateCharacter(ICharacter character)
{
return characterskillpoints.CreateCharacter(character);
}
        public bool StartGame(ICharacter character, bool ifUserIsSigned)
{
if(character!=null && ifUserIsSigned==true)
{
return true;
//Start the game
}
else
{
return false;
//Throw exception
}
}
}
}

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:

public void CreateCharacter(ICharacter character)
{
if(character is Barbarian)
{
characterskillpoints.GiveOutSkillPointsForBarbarian();
}
else if(character is Paladin)
{
characterskillpoints.GiveOutSkillPointsForPaladin();
}
else if (character is Mage)
{
characterskillpoints.GiveOutSkillPointsForMage();
}
else if (character is Thief)
{
characterskillpoints.GiveOutSkillPointsForThief();
}
}

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 :)

namespace DependencyInjectionTests
{
class GameServerClassTest
{
ICharacterSkillPoints characterskillpoints;
GameServer gameserver;
        [SetUp]
public void TestSetup()
{
ILoginValidator loginvalidator = new LoginValidator();
IPasswordValidator passwordvalidator = new PasswordValidator();
characterskillpoints = new CharacterSkillPoints();
            gameserver = new GameServer(loginvalidator, passwordvalidator, characterskillpoints);
}
        ICharacter CreateCharacter()
{
return characterskillpoints.CreateCharacter(new Mage());
}
        [Test]
public void start_the_game_test_correctly()
{
ICharacter character = CreateCharacter();
            bool ifvalidate = gameserver.RegisterUser("assd12", "adasd123@");
            bool ifGameIsStarted = gameserver.StartGame(character, ifvalidate);
            Assert.IsTrue(ifGameIsStarted);
}
        [Test]
public void start_the_game_test_not_correctly_with_bad_login_and_password()
{
ICharacter character = CreateCharacter();
            bool ifvalidate = gameserver.RegisterUser("assd", "adasd12");
            bool ifGameIsStarted = gameserver.StartGame(character, ifvalidate);
            Assert.IsFalse(ifGameIsStarted);
}
        [Test]
public void start_the_game_test_not_correctly_without_created_character()
{
bool ifvalidate = gameserver.RegisterUser("assd12", "adasd123@");
            bool ifGameIsStarted = gameserver.StartGame(null, ifvalidate);
            Assert.IsFalse(ifGameIsStarted);
}
}
}

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.

namespace DependencyInjectionTests
{
class GameServerClassTest
{
//other variables
        Mock<ICharacter> characterMock;
ICharacter character;
[SetUp]
public void TestSetup()
{
characterMock = new Mock<ICharacter>();
character = characterMock.Object;

//other dependencies
}
}
}

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 :)

bool ifGameIsStarted = gameserver.StartGame(character, ifvalidate);

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.

namespace Dependency_Injection___Inversion_of_Control
{
class WebServer
{
static GameServer gameServer;
        static void Main(string[] args)
{
var loginvalidator = new LoginValidator();
var passwordvalidator = new PasswordValidator();
var characterskillpoints = new CharacterSkillPoints();
gameServer = new GameServer(loginvalidator, passwordvalidator, characterskillpoints);
            bool ifUserIsLoginIn = LogIn();
            ICharacter createdCharacter = CreateCharacter();
            StartGame(createdCharacter, ifUserIsLoginIn);
            Console.ReadKey();
}
        static bool LogIn()
{
bool ifvalidate = gameServer.RegisterUser("assd12", "adasd123@");
            if (ifvalidate)
{
Console.WriteLine("Register user");
}
else
{
Console.WriteLine("Login or password are incorrect!");
}
            return ifvalidate;
}
        static ICharacter CreateCharacter()
{
ICharacter character = gameServer.CreateCharacter(new Barbarian());
            Console.WriteLine("Skill points after give out.");
            Console.WriteLine(character.Strength);
Console.WriteLine(character.Stamina);
            return character;
}
        static void StartGame(ICharacter character, bool ifvalidate)
{
bool ifGameIsStarted = gameServer.StartGame(character, ifvalidate);
            if (ifGameIsStarted)
{
Console.WriteLine("Start the game");
}
else
{
Console.WriteLine("Something went wrong!");
}
}
}
}

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:


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

namespace Dependency_Injection___Inversion_of_Control
{
public interface ICharacterRace
{
ICharacterRace CreateCharacterRace(ICharacterRace characterrace);
}
}

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:

ILoginValidator loginvalidator;
IPasswordValidator passwordvalidator;
ICharacterSkillPoints characterskillpoints;
ICharacterRace characterrace;
public GameServer(ILoginValidator loginvalidator, IPasswordValidator passwordvalidator, ICharacterSkillPoints characterskillpoints, ICharacterRace characterrace)
{
this.loginvalidator = loginvalidator;
this.passwordvalidator = passwordvalidator;
this.characterskillpoints = characterskillpoints;
this.characterrace = characterrace;
}

And the method that calls the ICharacterRace interface method.

public ICharacterRace CreateCharacterRace(ICharacterRace characterrace)
{
return characterrace.CreateCharacterRace(characterrace);
}

And in the client.

namespace Dependency_Injection___Inversion_of_Control
{
class WebServer
{
static GameServer gameServer;
        static void Main(string[] args)
{
var loginvalidator = new LoginValidator();
var passwordvalidator = new PasswordValidator();
var characterskillpoints = new CharacterSkillPoints();
gameServer = new GameServer(loginvalidator, passwordvalidator, characterskillpoints, new ICharacterRace());
            // other instructions
}

// other methods
}
}

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.

namespace DependencyInjectionTests
{
class GameServerClassTest
{
ICharacterSkillPoints characterskillpoints;
GameServer gameserver;
        Mock<ICharacterRace> characterRaceMock;
Mock<ICharacter> characterMock;
ICharacter character;
        [SetUp]
public void TestSetup()
{
characterRaceMock = new Mock<ICharacterRace>();
characterMock = new Mock<ICharacter>();
            character = characterMock.Object;
            ILoginValidator loginvalidator = new LoginValidator();
IPasswordValidator passwordvalidator = new PasswordValidator();
characterskillpoints = new CharacterSkillPoints();
            gameserver = new GameServer(loginvalidator, passwordvalidator, characterskillpoints, characterRaceMock.Object);
}
        [Test]
public void test_race_attributes()
{
characterRaceMock.Setup(x => x.CreateCharacterRace(It.IsAny<ICharacterRace>())).Returns(() => characterRaceMock.Object);
            Assert.IsInstanceOf(typeof(Mock), characterRaceMock);
}
        // other tests
}
}

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 my blog devman.pl: http://devman.pl/programtech/dependency-injection-inversion-of-control-2/

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. :)