Lesson 10.1: Refactoring Base Class for Player, Monster, and Trader

We have some duplicate code in the Player, Monster, and Trader class. In this lesson, we’ll create a base class to eliminate that duplication.




Lesson Steps

Step 1: Create the class Engine\Models\LivingEntity.cs

This class will hold all the common properties and functions that a living creature has in the game. For example, name, hit points, gold, and inventory.

We currently have some differences with those properties. The Monster class has “CurrentHitPoints” and “MaximumHitPoints”. The Player class only has “HitPoints”. But, the Player class really needs MaximumHitPoints, for when we add healing – so the Player cannot heal to more hit points than their maximum.


Notice that LivingEntity inherits from BaseNotificationClass. So, it can use the functions in BaseNotificationClass.

We are going to change Player, Monster, and Trader to inherit from LivingEntity. Because LivingEntity inherits from BaseNotificationClass, that means LivingEntity’s “children” will have the functions and properties from BaseNotificationClass – their “grand-parent”.


On line 7, notice that LivingEntity has the scope of “abstract”. That means you cannot instantiate a LivingEntity class. You can instantiate one of its children, which will have all the functions and properties from LivingEntity. But, you cannot create a LivingEntity object on its own.


On line 58, the LivingEntity constructor is declared as “protected”. Something that is protected can only been seen/used by the children of this class.

When you instantiate a Player class, the constructor in Player.cs will run, and it will run the constructor in LivingEntity.cs. This is how you can ensure all child classes run any initialization code need for the base class.





Step 2: Modify Player.cs, Monster.cs, and Trader.cs

Now that we have a base class, we’ll have these classes derive from it.

They currently inherit from BaseNotificationClass. Change that to LivingEntity (in the code below, line 7 in Player.cs and line 3 in Monster and Trader).

Then, we can remove all the properties and functions from the child classes that are now in the base class.









Step 3: Modify Engine\ViewModels\GameSession.cs

Because the child classes did not have the same names for all the properties, we need to change any places where the old names were used, to use the new name in the base class.

For example, in LivingEntity, we have the property CurrentHitPoints. The Player class had the property “HitPoints”. So now, we need to change GameSession to use “CurrentHitPoints”.


On line 99, change “HitPoints” to “CurrentHitPoints”, and add line 100 (in the code below) to set the player object’s MaximumHitPoints value.


In the AttackCurrentMonster function (line 228 below) there are a few changes to make.

Change the monster’s “HitPoints” to “CurrentHitPoints” on lines 245 and 250.

Change “RewardGold” to “Gold” on lines 258 and 259.

Change the “foreach” loop on line 261 to the new one shown in the code below. In the old version, the Monster’s Inventory property held ItemQuantity objects. Those objects had two properties: ItemID and Quantity.

The new shared Inventory property in LivingEntity holds GameItem objects. So, we can get the GameItem objects directly from the Monster’s Inventory and add them to the Player’s Inventory.

Change the player’s “HitPoints” to “CurrentHitPoints” on lines 281, 286, and 292.

Hose are all the changes we need to make to GameSession.cs





Step 4: Modify Engine\Factories\MonsterFactory.cs

The MonsterFactory used to add ItemQuantity objects to the Monster’s Inventory. But now, Inventory holds GameItem objects. So, we need to change the MonsterFactory to create GameItems and add them to the Monster’s inventory.

Change line 48 to the line below. This will instantiate a GameItem object and add it to the Monster’s Inventory.





Step 5: Modify WPFUI\MainWindow.xaml

We also need to fix the changed property names used in the UI.

In this screen, we used “HitPoints” on lines 53 and 153. Change those to “CurrentHitPoints”.





Step 6: Test the game

As always, after making changes, run the program and see if it works.

When refactoring, you aren’t adding new features or fixing bugs. You’re only making the code a little cleaner, and easier to work with. So, the program should run exactly the same as it did before.

It’s best to not combine refactoring with other changes (bug fixes or feature changes). If you do, and the program doesn’t work, it’s often difficult to know what caused the problem.

So, when you refactor, only refactor. When you are done testing the refactoring, check in your code to your source control. Then, do your bug fixes or new features. That way, if there is a problem, you can revert your source code back to the working (post-refactoring) code and retry your changes.



Return to main page

Leave a Reply

Your email address will not be published. Required fields are marked *