Refactoring Day 31 : Replace conditional with Polymorphism


The last day of refactoring comes from Fowlers refactoring catalog and can be found here.

This shows one of the foundations of Object Oriented Programming which is Polymorphism. The concept here is that in instances where you are doing checks by type, and performing some type of operation, it’s a good idea to encapsulate that algorithm within the class and then use polymorphism to abstract the call to the code.

   1: public abstract class Customer

   2: {

   3: }

   4:  

   5: public class Employee : Customer

   6: {

   7: }

   8:  

   9: public class NonEmployee : Customer

  10: {

  11: }

  12:  

  13: public class OrderProcessor

  14: {

  15:     public decimal ProcessOrder(Customer customer, IEnumerable<Product> products)

  16:     {

  17:         // do some processing of order

  18:         decimal orderTotal = products.Sum(p => p.Price);

  19:  

  20:         Type customerType = customer.GetType();

  21:         if (customerType == typeof(Employee))

  22:         {

  23:             orderTotal -= orderTotal * 0.15m;

  24:         }

  25:         else if (customerType == typeof(NonEmployee))

  26:         {

  27:             orderTotal -= orderTotal * 0.05m;

  28:         }

  29:  

  30:         return orderTotal;

  31:     }

  32: }

</div> </div>

As you can see here, we’re not leaning on our inheritance hierarchy to put the calculation, or even the data needed to perform the calculation lest we have a SRP violation. So to refactor this we simply take the percentage rate and place that on the actual customer type that each class will then implement. I know this is really remedial but I wanted to cover this as well as I have seen it in code.

   1: public abstract class Customer

   2: {

   3:     public abstract decimal DiscountPercentage { get; }

   4: }

   5:  

   6: public class Employee : Customer

   7: {

   8:     public override decimal DiscountPercentage

   9:     {

  10:         get { return 0.15m; }

  11:     }

  12: }

  13:  

  14: public class NonEmployee : Customer

  15: {

  16:     public override decimal DiscountPercentage

  17:     {

  18:         get { return 0.05m; }

  19:     }

  20: }

  21:  

  22: public class OrderProcessor

  23: {

  24:     public decimal ProcessOrder(Customer customer, IEnumerable<Product> products)

  25:     {

  26:         // do some processing of order

  27:         decimal orderTotal = products.Sum(p => p.Price);

  28:  

  29:         orderTotal -= orderTotal * customer.DiscountPercentage;

  30:  

  31:         return orderTotal;

  32:     }

  33: }

</div> </div>

This is part of the 31 Days of Refactoring series. For a full list of Refactorings please see the original introductory post.

Refactoring Day 30 : Return ASAP