Lesson 12.6: Refactoring after adding Actions

We’ve made many changes recently. Let’s take a moment to do some refactoring.

 

 

 

Lesson Steps

Step 1: Create Engine\Actions\BaseAction.cs

All our action classes will share some similar functions. So, let’s put them in a base class.

 

We never need a BaseAction object. We’ll only instantiate children of BaseAction. So, we’re making this an “abstract” class, which cannot be instantiated on its own – only through its child classes.

 

Move the OnActionPerformed event and ReportResult function into BaseAction. Notice that the event is still public, because other objects will subscribe to this event (the LivingEntity class).

However, the ReportResult function and _itemInUse variable are protected. This is so BaseAction’s child classes can use them.

 

I’ve also created a protected BaseAction constructor that accepts a GameItem parameter “itemInUse” and saves it to the protected “_itemInUse” variable.

 

BaseAction.cs

 

 

Step 2: Modify Engine\Actions\AttackWithWeapon.cs and Heal.cs

Now we can remove the code in the new base class from its children.

 

Remove the OnActionPerformed event, the ReportResult function, the _weapon variable from AttackWithWeapon, and the

 

I’ve also renamed the “weapon” parameter and variable from AttackWithWeapon, and the “item” parameter and variable from Heal. We’ll use the _itemInUse variable from BaseAction.

 

We’re combining an abstract base class with an interface here.

If we implemented all the interface requirements in the base class, we could change BaseAction to “public abstract class BaseAction : IAction”, and remove the ” : IAction” from the child classes. The child classes would still be IAction objects, because their parent class is an IAction object.

But, in this situation, we cannot put the Execute function (which is required in the interface) in the base class. Each Action child class has unique code in their Execute function. So, we need to have ” : IAction” in each child class.

 

AttackWithWeapon.cs

 

Heal.cs

 

 

Step 3: Run the unit tests and play the game, to ensure the refactoring changes didn’t break anything.

 

Return to main page

4 thoughts on “Lesson 12.6: Refactoring after adding Actions

  1. Hi Scott,

    great lessons, many thanks for that.

    To get rid of IAction in child actions we could make BaseAction implements IAction and declare abstract Execute method in there and then override the Execute method in child actions.
    Is that a better approach or it doesn’t matter?

    1. You’re welcome Gee,

      We could do that, although I prefer using the interface method. With a small program like this, it does not make a big difference. But, it might if we started to add many more child classes.

      With many different child classes, you could have many child classes that act very differently (maybe a poison that causes damage for each turn). Then you might find that you need some of the functions from the abstract base, but you don’t need other functions. Then, your child classes start acting differently. If we just use an interface, we do not need to override functions that we might not need to use – or start creating additional base classes that are similar to the first one, but slightly different.

      With base classes in larger programs that have many different business classes, you might start to see problems that lead to many programmers preferring Composition over inheritance.

      Let me know if you still have questions.

    1. I think you’re correct that _itemInUse could be private. But, if you make more classes in the future that implement IAction, their Execute() functions might need access to _itemInUse.

Leave a Reply

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