Pages

11.4.10

Implementing a Motor Race Using the Strategy Design Pattern

Introduction


In this article, we will learn about the Strategy Pattern by implementing it on a motor racing game. Strategy pattern is one of the many design patterns defined by the Gang of Four (GoF). A design pattern is a definition of a problem that other developers have faced before you, and they found a solution that might help you if you’re facing the same problem or a similar one. To know more about design patterns, please visit the www.dofactory.com site.

Background


Strategy pattern is used when you have objects that have many things in common but they also have different ways of behavior in certain situations. In this article, we'll design a small game (Motor Race), and we'll use Strategy pattern to implement the design. Again, this design is inspired by a solution that previous developers faced before and where they came up with this design pattern.

Game description


The game is a racing between different mobility motors; cars, motor-bikes, and buses; they all have many shared properties and behaviors, like, Motor Name, Color, but they also have different behaviors on certain points, like: the way that they look and get displayed, or the way they move. Cars and buses move on four wheels, but motor-bikes move on two wheels. The game will have many cars, motor-bikes, and buses racing. All the cars will have the same appearance, the same applies for motor-bikes and buses. Our goal now is to put a design for this game to be used in the client code, keeping in mind that we want our design to be reusable, meaning that if any time I decide to add a new mobility option (like a bike), I don’t want to rewrite the code for it, I'd just want to add the minimum amount of code and reuse the code that is already written. We also need our design not to have any redundant code, meaning if I have a code segment that is repeated in different places, I should group them in one place. Another thing to mention is that we’ll use C# to implement our design.


Using the code


First of all, let’s agree that we have three different types of objects that belong to the same group, and they have things in common; cars, motor-bikes, and buses are all mobility motors, so why don’t we make just one class for all of them and call it MobilityMotor and put all the shared properties in it, and then inherit this class into Car, MotorBike, and Bus? But the pattern doesn’t say so, because it's a better practice to implement an interface rather than extend and inherit a class, so what we should do now is create an interface and call it IMobilityMotor, putting the shared properties and methods there:

  1. // Code 1
  2.  
  3. using System;
  4. namespace MotorRace
  5.  
  6. {
  7.     public interface IMobilityMotor
  8.     {
  9.        // We will add new property later in this
  10.        // article to set the moving behavior of the object
  11.        string MotorName
  12.        {
  13.                get;
  14.                set;
  15.        }
  16.        string MotorColor
  17.        {
  18.                get;
  19.                set;
  20.        }
  21.        void Move();
  22.        void Display();
  23.     }
  24. }

Now, let's implement this interface three times, one for a Car class, one for a MotorBike class, and one for a Bus class. I'll show here how to make a Car class, and you can do the same for the MotorBike and Bus classes.

  1. // Code 2
  2.  
  3. using System;
  4. namespace MotorRace
  5. {
  6.     public class Car : IMobilityMotor
  7.     {
  8.         private string motorName;
  9.         private string motorColor;
  10.         // We will add new property later in this article
  11.         // to set the moving behavior of the object
  12.         public Car()
  13.         {
  14.             motorName = string.Empty;
  15.             motorColor = string.Empty;
  16.         }
  17.         public string MotorName
  18.         {
  19.             get
  20.             {
  21.                 return motorName;
  22.             }
  23.             set
  24.             {
  25.                 motorName = value;
  26.             }
  27.         }
  28.         public string MotorColor
  29.         {
  30.             get
  31.             {
  32.                 return motorColor;
  33.             }
  34.             set
  35.             {
  36.                 motorColor = value;
  37.             }
  38.         }
  39.         public void Move()
  40.         {
  41.             // We will add code later
  42.             // in this article to move object
  43.         }
  44.         public void Display()
  45.         {
  46.             // Add code here to display car,
  47.             // this code is only for car objects
  48.         }
  49.     }
  50. }

Now, just create two new classes for MotorBike and Bus, doing the same as you did for the Car. You will end up with a result that’s shown in the diagram below. Don't pay attention now to the MovingBehavior property in the MotorBike, Car, and Bus classes, you’ll understand it later in this article.



And now, we want to create classes to implement the moving behaviors, so we’ll create an interface and call it IMovingBehavior. This interface will be implemented by two classes: FourWheelsMoving and TwoWheelsMoving, and it will contain a Move() method that will be implemented by the two classes, as follows:

  1. // Code 3
  2.  
  3. using System;
  4. namespace MotorRace
  5. {
  6.     public interface IMovingBehavior
  7.     {
  8.         void Move();
  9.     }
  10. }

Now, let’s implement the IMovingBehavior interface by the FourWheelsMoving class, and then also by the TwoWheelsMoving class.

  1. // Code 4
  2. using System;
  3. namespace MotorRace
  4. {
  5.     public class FourWheelsMoving : IMovingBehavior
  6.     {
  7.         public FourWheelsMoving()
  8.         {
  9.         }
  10.         public void Move()
  11.         {
  12.             // We will add code later
  13.             // in this article to move object
  14.         }
  15.     }
  16. }

Let’s now understand what we have done. We have created two interfaces: one for a mobility motor (cars, motor-bikes, and buses), and another one for the way they move. As we mentioned before, there are two ways to move, either on four wheels or on two wheels. So, we implemented two classes from the IMovingBehavior interface, and we implemented three classes from the IMobilityMotor interface. In this design, we implement a high level of reusability, so if we need to add a new motor in the future, for example, a bike, or a lorry, all that we need to do is to implement a new class for it from IMobilityMotor, and if we have a new motor that moves on three wheels, or a motor that flies like a helicopter, then we just implement a new behavior class from the IMovingBehavior interface.

But the question now is how will a Car object know what its behavior is and the way it should move? To solve this, let’s add a new property to IMobilityMotor to set the correct behavior, and we’ll also add an implementation of this property in the Car, MotorBike, and Bus classes, as follows:

  1. // Code 1 (Updated)
  2.  
  3. using System;
  4. namespace MotorRace
  5. {
  6.     public interface IMobilityMotor
  7.     {
  8.         // We will add new property later in this
  9.         // article to set the moving behavior of the object
  10.         IMovingBehavior MovingBehavior
  11.         {
  12.             get;
  13.             set;
  14.         }
  15.         .
  16.         .
  17.         .
  18.         .

  1. // Code 2 (Updated)
  2. using System;
  3. namespace MotorRace
  4. {
  5.     public class Car
  6.     {
  7.         private string motorName;
  8.         private string motorColor;
  9.         // We will add new property later in this
  10.         // article to set the moving behavior of the object
  11.         IMovingBehavior movingBehavior;
  12.         public IMovingBehavior MovingBehavior
  13.         {
  14.             get
  15.             {
  16.                 return movingBehavior;
  17.             }
  18.             set
  19.             {
  20.                 movingBehavior = value;
  21.             }
  22.         }
  23.  
  24.         .
  25.         .
  26.         .
  27.         .
  28.         .

Now, we should implement the Move() method in the Car, MotorBike, and Bus classes, as follows:

  1. // Code 2 (Updated)
  2. using System;
  3. namespace MotorRace
  4. {
  5.     public class Car
  6.     {
  7.  
  8.         .
  9.         .
  10.         .
  11.         .
  12.         .
  13.  
  14.         public void Move()
  15.         {
  16.             movingBehavior.Move();
  17.             /* Here, the Car object will know that
  18.             movingBehavior is of type
  19.             FourWheelsMoving, because when its value was set
  20.             it was initiated to FourWheelsMoving instance,
  21.             so when we call the Move() method,
  22.             it will call the Move() method
  23.             in FourWheelsMoving class. */
  24.         }
  25.  
  26.         .
  27.         .
  28.         .
  29.         .
  30.         .



Conclusion


So we can now get to this conclusion: the Strategy pattern defines a family of algorithms, encapsulating each one by grouping similar algorithms in one place and separating the parts that vary.

2 comments:

  1. How does the Car class know that it should use FourWheelsMoving class or TwoWheelsMoving class?

    ReplyDelete
  2. In the client code, when create the Car object, you can set the MovingBehavior property to either FourWheelsMoving or TwoWheelsMoving.

    Alternatively, you can make a constructor that accepts a parameter of type IMovingBehavior and set the MovingBehavior property there.

    ReplyDelete

Promotional Code for Udemy ServiceNow CIS - HR Practice Tests

If you're planning to become ServiceNow Certified Implementation Specialist - Human Resources (CIS-HR), you can prepare for the exam usi...