Permalink
Browse files

Dependency Injection code

Added code for Dependency Injection design pattern
  • Loading branch information...
1 parent 9093af8 commit 8d2d5a845f290f3fb7b2ef80f411d1dd69878e38 @ScottLilly committed Aug 25, 2016
View
@@ -252,4 +252,5 @@ paket-files/
*.sln.iml
#Subversion
-*.svn
+*.svn
+.cr/Settings.xml
@@ -0,0 +1,40 @@
+using System;
+
+namespace Engine.DependencyInversionPattern.NonPatternVersion
+{
+ public class Player
+ {
+ public string Name { get; private set; }
+ public int ExperiencePoints { get; private set; }
+ public int Gold { get; private set; }
+
+ public Player(string name, int experiencePoints, int gold)
+ {
+ Name = name;
+ ExperiencePoints = experiencePoints;
+ Gold = gold;
+ }
+
+ public static Player CreateNewPlayer(string name)
+ {
+ if(string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("Player name cannot be empty.");
+ }
+
+ // Create a Data Mapper object, to use to connect with the database
+ PlayerDataMapper _playerDataMapper = new PlayerDataMapper();
+
+ // Throw an exception if there is already a player with this name in the database.
+ if(_playerDataMapper.PlayerNameExistsInDatabase(name))
+ {
+ throw new ArgumentException("Player name already exists.");
+ }
+
+ // Add the player to the database.
+ _playerDataMapper.InsertNewPlayerIntoDatabase(name);
+
+ return new Player(name, 0, 10);
+ }
+ }
+}
@@ -0,0 +1,51 @@
+using System.Data;
+using System.Data.SqlClient;
+
+namespace Engine.DependencyInversionPattern.NonPatternVersion
+{
+ public class PlayerDataMapper
+ {
+ private readonly string _connectionString =
+ "Data Source=(local);Initial Catalog=MyGame;Integrated Security=True";
+
+ public bool PlayerNameExistsInDatabase(string name)
+ {
+ using(SqlConnection connection = new SqlConnection(_connectionString))
+ {
+ connection.Open();
+
+ using(SqlCommand playersWithThisName = connection.CreateCommand())
+ {
+ playersWithThisName.CommandType = CommandType.Text;
+ playersWithThisName.CommandText = "SELECT count(*) FROM Player WHERE 'Name' = @Name";
+
+ playersWithThisName.Parameters.AddWithValue("@Name", name);
+
+ // Get the number of player with this name
+ var existingRowCount = (int)playersWithThisName.ExecuteScalar();
+
+ // Result is 0, if no player exists, or 1, if a player already exists
+ return existingRowCount > 0;
+ }
+ }
+ }
+
+ public void InsertNewPlayerIntoDatabase(string name)
+ {
+ using(SqlConnection connection = new SqlConnection(_connectionString))
+ {
+ connection.Open();
+
+ using(SqlCommand playersWithThisName = connection.CreateCommand())
+ {
+ playersWithThisName.CommandType = CommandType.Text;
+ playersWithThisName.CommandText = "INSERT INTO Player ([Name]) VALUES (@Name)";
+
+ playersWithThisName.Parameters.AddWithValue("@Name", name);
+
+ playersWithThisName.ExecuteNonQuery();
+ }
+ }
+ }
+ }
+}
@@ -0,0 +1,8 @@
+namespace Engine.DependencyInversionPattern.PatternVersion
+{
+ public interface IPlayerDataMapper
+ {
+ bool PlayerNameExistsInDatabase(string name);
+ void InsertNewPlayerIntoDatabase(string name);
+ }
+}
@@ -0,0 +1,45 @@
+using System;
+
+namespace Engine.DependencyInversionPattern.PatternVersion
+{
+ public class Player
+ {
+ public string Name { get; private set; }
+ public int ExperiencePoints { get; private set; }
+ public int Gold { get; private set; }
+
+ public Player(string name, int experiencePoints, int gold)
+ {
+ Name = name;
+ ExperiencePoints = experiencePoints;
+ Gold = gold;
+ }
+
+ public static Player CreateNewPlayer(string name, IPlayerDataMapper playerDataMapper = null)
+ {
+ // If a PlayerDataMapper was not passed in, use a real one.
+ // This allows us to pass in a "mock" PlayerDataMapper (for testing),
+ // but use a real PlayerDataMapper, when running the program.
+ if(playerDataMapper == null)
+ {
+ playerDataMapper = new PlayerDataMapper();
+ }
+
+ if(string.IsNullOrWhiteSpace(name))
+ {
+ throw new ArgumentException("Player name cannot be empty.");
+ }
+
+ // Throw an exception if there is already a player with this name in the database.
+ if(playerDataMapper.PlayerNameExistsInDatabase(name))
+ {
+ throw new ArgumentException("Player name already exists.");
+ }
+
+ // Add the player to the database.
+ playerDataMapper.InsertNewPlayerIntoDatabase(name);
+
+ return new Player(name, 0, 10);
+ }
+ }
+}
@@ -0,0 +1,51 @@
+using System.Data;
+using System.Data.SqlClient;
+
+namespace Engine.DependencyInversionPattern.PatternVersion
+{
+ public class PlayerDataMapper : IPlayerDataMapper
+ {
+ private readonly string _connectionString =
+ "Data Source=(local);Initial Catalog=MyGame;Integrated Security=True";
+
+ public bool PlayerNameExistsInDatabase(string name)
+ {
+ using(SqlConnection connection = new SqlConnection(_connectionString))
+ {
+ connection.Open();
+
+ using(SqlCommand playersWithThisName = connection.CreateCommand())
+ {
+ playersWithThisName.CommandType = CommandType.Text;
+ playersWithThisName.CommandText = "SELECT count(*) FROM Player WHERE 'Name' = @Name";
+
+ playersWithThisName.Parameters.AddWithValue("@Name", name);
+
+ // Get the number of player with this name
+ var existingRowCount = (int)playersWithThisName.ExecuteScalar();
+
+ // Result is 0, if no player exists, or 1, if a player already exists
+ return existingRowCount > 0;
+ }
+ }
+ }
+
+ public void InsertNewPlayerIntoDatabase(string name)
+ {
+ using(SqlConnection connection = new SqlConnection(_connectionString))
+ {
+ connection.Open();
+
+ using(SqlCommand playersWithThisName = connection.CreateCommand())
+ {
+ playersWithThisName.CommandType = CommandType.Text;
+ playersWithThisName.CommandText = "INSERT INTO Player ([Name]) VALUES (@Name)";
+
+ playersWithThisName.Parameters.AddWithValue("@Name", name);
+
+ playersWithThisName.ExecuteNonQuery();
+ }
+ }
+ }
+ }
+}
@@ -57,6 +57,11 @@
<Compile Include="CommandPattern\PatternVersion_WithUndo\Withdraw.cs" />
<Compile Include="DataMapperPattern\Customer.cs" />
<Compile Include="DataMapperPattern\CustomerDataMapper.cs" />
+ <Compile Include="DependencyInversionPattern\NonPatternVersion\Player.cs" />
+ <Compile Include="DependencyInversionPattern\NonPatternVersion\PlayerDataMapper.cs" />
+ <Compile Include="DependencyInversionPattern\PatternVersion\IPlayerDataMapper.cs" />
+ <Compile Include="DependencyInversionPattern\PatternVersion\Player.cs" />
+ <Compile Include="DependencyInversionPattern\PatternVersion\PlayerDataMapper.cs" />
<Compile Include="FactoryPattern\NonPatternVersion\Player.cs" />
<Compile Include="FactoryPattern\PatternVersion_ExternalFactory\Player.cs" />
<Compile Include="FactoryPattern\PatternVersion_ExternalFactory\PlayerFactory.cs" />
@@ -0,0 +1,20 @@
+using System;
+using Engine.DependencyInversionPattern.NonPatternVersion;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace TestEngine.DependencyInversionPattern.NonPatternVersion
+{
+ [TestClass]
+ public class TestPlayer
+ {
+ // Test that we receive an exception, if the name parameter is an empty string.
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void Test_CreateNewPlayer_EmptyName()
+ {
+ Player player = Player.CreateNewPlayer("");
+ }
+
+ // Other tests would require a running database, which might have problems.
+ }
+}
@@ -0,0 +1,22 @@
+using Engine.DependencyInversionPattern.PatternVersion;
+
+namespace TestEngine.DependencyInversionPattern.PatternVersion
+{
+ public class MockPlayerDataMapper : IPlayerDataMapper
+ {
+ // This property holds the value for PlayerNameExistsInDatabase to return.
+ // This lets us "mock" the results that we would receive from a real database.
+ public bool ResultToReturn { get; set; }
+
+ // These functions implement the IPlayerDataMapper interface.
+ public bool PlayerNameExistsInDatabase(string name)
+ {
+ // This is whatever answer we need, for the current unit test.
+ return ResultToReturn;
+ }
+
+ public void InsertNewPlayerIntoDatabase(string name)
+ {
+ }
+ }
+}
@@ -0,0 +1,59 @@
+using System;
+using Engine.DependencyInversionPattern.PatternVersion;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace TestEngine.DependencyInversionPattern.PatternVersion
+{
+ [TestClass]
+ public class TestPlayer
+ {
+ // Should receive an exception, because the name is an empty string.
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void Test_CreateNewPlayer_EmptyName()
+ {
+ Player player = Player.CreateNewPlayer("");
+ }
+
+ // Should still receive an exception, because the name is an empty string.
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void Test_CreateNewPlayer_EmptyName_MockedDataMapper()
+ {
+ MockPlayerDataMapper mockPlayerDataMapper = new MockPlayerDataMapper();
+
+ Player player = Player.CreateNewPlayer("", mockPlayerDataMapper);
+ }
+
+ // Should receive an exception, because we set the mock PlayerDataMapper
+ // to say the player name already exists in the database.
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentException))]
+ public void Test_CreateNewPlayer_AlreadyExistsInDatabase()
+ {
+ MockPlayerDataMapper mockPlayerDataMapper = new MockPlayerDataMapper();
+
+ mockPlayerDataMapper.ResultToReturn = true;
+
+ Player player = Player.CreateNewPlayer("Test", mockPlayerDataMapper);
+ }
+
+ // Should succeed, because we set the mock PlayerDataMapper
+ // to say the player name does not already exist in the database.
+ // Also, when it calls the mock InsertNewPlayerIntoDatabase,
+ // the mock mapper will not need a database running.
+ [TestMethod]
+ public void Test_CreateNewPlayer_DoesNotAlreadyExistInDatabase()
+ {
+ MockPlayerDataMapper mockPlayerDataMapper = new MockPlayerDataMapper();
+
+ mockPlayerDataMapper.ResultToReturn = false;
+
+ Player player = Player.CreateNewPlayer("Test", mockPlayerDataMapper);
+
+ Assert.AreEqual("Test", player.Name);
+ Assert.AreEqual(0, player.ExperiencePoints);
+ Assert.AreEqual(10, player.Gold);
+ }
+ }
+}
@@ -54,6 +54,9 @@
<ItemGroup>
<Compile Include="CommandPattern\PatternVersion\TestCommandPattern.cs" />
<Compile Include="CommandPattern\PatternVersion_WithUndo\TestCommandPattern.cs" />
+ <Compile Include="DependencyInversionPattern\NonPatternVersion\TestPlayer.cs" />
+ <Compile Include="DependencyInversionPattern\PatternVersion\MockPlayerDataMapper.cs" />
+ <Compile Include="DependencyInversionPattern\PatternVersion\TestPlayer.cs" />
<Compile Include="FactoryPattern\TestFactoryPattern_NonPatternVersion.cs" />
<Compile Include="FactoryPattern\TestFactoryPattern_PatternVersion_ExternalFactory.cs" />
<Compile Include="FactoryPattern\TestFactoryPattern_PatternVersion_InternalFactory.cs" />

0 comments on commit 8d2d5a8

Please sign in to comment.