Suppose you have a conditional statement such as a switch or if-else that performs various actions depending on an object’s type:
It is often beneficial to try to avoid lengthy switch/if-else constructions. This post demonstrates how these can be refactored using polymorphism.
Consider the following Employee class which uses a conditional statement to return a salary depending on employee types Apprentice, Developer, Manager:
public class Employee { public int GetSalary(EmployeeType type) { var salary = 0; switch (type) { case EmployeeType.Apprentice: salary = 10000; break; case EmployeeType.Developer: salary = 20000; break; case EmployeeType.Manager: salary = 30000; break; } return salary; } }
Employee type enumerations as follows:
public enum EmployeeType { Manager = 0, Developer, Apprentice }
An example usage of this in main program could be as follows:
static void Main(string[] args) { var employee = new Employee(); Console.WriteLine("Apprentice salary = " + employee.GetSalary(EmployeeType.Apprentice)); Console.WriteLine("Developer salary = " + employee.GetSalary(EmployeeType.Developer)); Console.WriteLine("Manager salary = " + employee.GetSalary(EmployeeType.Manager)); }
Giving the following output as expected:
This is perfectly fine. However when you you catch yourself using a switch statement, or an if-else statement, consider using the object-orientation first. By creating abstractions for known behaviours, your application will be a lot cleaner and easier to manage.
For one one thing you will no longer have to navigate through the code to find all usages of GetSalary each time the EmployeeType is modified.
“Polymorphism lets you have different behavior for sub types, while keeping a consistent contract.”
So in this example we create an interface which provides us with an abstraction that allows us to contain the behaviour necessary to calculate the salary of an employee:
public interface IEmployee { int GetSalary(); }
Then create concrete implementations of the interface :
public class Apprentice : IEmployee { public int GetSalary() { return 10000; } } public class Developer : IEmployee { public int GetSalary() { return 20000; } } public class Manager : IEmployee { public int GetSalary() { return 30000; } }
So that in our updated implementation we do away with the need for the enumeration:
static void Main(string[] args) { Console.WriteLine("Apprentice salary = " + new Apprentice().GetSalary()); Console.WriteLine("Developer salary = " + new Developer().GetSalary()); Console.WriteLine("Manager salary = " + new Manager().GetSalary()); }
Resulting in the same output using simpler code: