This is an archived version of the course. Please find the latest version of the course on the main webpage.

Chapter 7: More classes for your robot!

Implementing new classes

face Josiah Wang

The next step will be to implement these new classes and refactor your code appropriately! After refactoring, hopefully your code will read like objects interacting with one another.

Here are some tips and my thought processes.

Refactor incrementally

Perform the refactoring incrementally, making sure that your code still behaves correctly after any updates. You can start with simpler classes that do not depend on other classes (Drink in my example). Then move on to Grid (which relies on Drink). Then update Robot and subsequently main.py to incorporate Grid (and perhaps Drink).

Be prepared to change!

As you implement your code, you may start to identify more classes that might be useful. For example, I ended up with a DrinkFactory class to create new drinks. The class is used by main.py to create new drinks for each Robot, and the drinks passed on to the Grid class to be placed onto a random corner cell. Feel free to update your design as you go along.

What did I end up changing?

Compared to my proposed class diagram from the previous page, I have discovered things that I did not anticipate before, and have readapted accordingly.

  • I found that RobotFactory needed to have Grid as an attribute since it needs this to construct each Robot. So I replaced the grid_size attribute with grid.
  • Created a DrinkFactory class to generate drinks.
  • Grid has taken on more responsibilities than I originally anticipated.
    • I delegated the task of generating random positions to Grid. Whenever RobotFactory wants to create a random position for a new Robot, it now asks Grid to do it on its behalf, since Grid knows better which cells are valid.
    • I let Grid decide where to place the drinks when adding. It is possible to delegate this job to a DrinkPositioner class (left for open future improvement)
  • I can even add a NavigationManager class in the future and move some of the navigation logic from main.py into its own class (left for open future improvement)

No need to be perfect!

Do not try to obtain the ‘perfect’ design (because there is probably none!) You can always refactor your code later on when the details get clearer, and when you realise that you might need more classes or that things can be done in a better way. Just make the immediate changes, make sure that your code still runs correctly, and then come back to refactor later. Remember that code correctness is more important than elegantly designed code!

Refactor your code!

Now, try designing and refactoring your robot code to introduce more object classes that interact with each other. Then update your code in main.py to reflect the new design.

You can simply use my design if you like. As mentioned, start with the most independent class first (Drink), and grow from there. Feel free to go through and analyse my solutions to learn from anything I have done. Do remember that my implementation is not necessarily the ‘best’ solution - there might be many different ways to achieve the same goal!

I’m purposely leaving this task open-ended and flexible. If you are in a hurry, you can just work on a small bit for now and then move on with the lesson. I actually spent about 1 hour 45 minutes refactoring my own code! You can come back and tweak your code later at your own pace, when you have more time and need to practise your OOP and OOAD skills a bit more! You will get better at it with more practice, and having a practical project like this is really helpful.