Los Techies : Blogs about software and anything tech!

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: }

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: }

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

Kick It on DotNetKicks.com
Posted Aug 28 2009, 12:38 PM by schambers

Comments

on 08-31-2009 11:56 AM

Agile/ALT.NET/Software Design A guide into OR/M implementation challenges: The Session Level Cache Build Your Own Data Access Layer: Lazy Loading A guide into OR/M implementation challenges: Laxy Loading Building Your Own Data Access Layer: Executing

Jordi wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 08-31-2009 1:01 PM

What should be done when the additional method in the Customer subclasses would really not be the responsibility of those subclasses? Adding the method would violate the SRP (as you say I think?), but not adding it leaves us with the typechecking conditionals.

Also, a related(?) case: What if there are multiple stores where orders can be placed that all have employee discounts, but they are not the same? It seems that now you have to either check the type of customer in the OrderProcessor class, or the type of store in the Customer classes.

schambers wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 08-31-2009 1:29 PM

@Jordi

Then the data that is used to determine the case should be placed on the class, like let's say an Enum that could be used polymorphically in the consuming class.

In this example you could create an enum called "CustomerType" and then on the base class have:

public abstract CustomerType Type { get; }

each subclass would expose it's customer type that can then be used via the abstraction.You would still need a conditional but the conditional isn't asserting the actual type and thus not being coupled to implementations.

Reflective Perspective - Chris Alcock » The Morning Brew #423 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #423
on 09-01-2009 3:42 AM

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #423

Samoys wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-03-2009 12:03 PM

lot about you

Roberto wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-04-2009 6:39 AM

cool blog

dilandinga wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-04-2009 1:09 PM

dA2fdp I bookmarked this link. Thank you for good job!

Frilith wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-10-2009 2:14 PM

Great site. Keep doing.,

Kalinwanpu wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-11-2009 4:48 AM

Very cute :-)))),

Laulith wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-11-2009 6:45 PM

Perfect work!,

Nawia wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 10-12-2009 9:29 AM

Very cute :-)))),

31 Days of Refactoring « Vincent Leung's .NET Tech Clips wrote 31 Days of Refactoring &laquo; Vincent Leung&#039;s .NET Tech Clips
on 10-28-2009 9:28 AM

Pingback from  31 Days of Refactoring « Vincent Leung's .NET Tech Clips

Kaiarith wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 11-02-2009 7:41 PM

I want to say - thank you for this!, <a href="webhardy.angelfire.com/soma-pharmacy-shipping-to-ky.html"">webhardy.angelfire.com/soma-pharmacy-shipping-to-ky.html">Soma">webhardy.angelfire.com/soma-pharmacy-shipping-to-ky.html">Soma Pharmacy Shipping To Ky</a>, [url="webhardy.angelfire.com/soma-pharmacy-shipping-to-ky.html"">webhardy.angelfire.com/soma-pharmacy-shipping-to-ky.html"]Soma Pharmacy Shipping To Ky[/url], webhardy.angelfire.com/soma-pharmacy-shipping-to-ky.html Soma Pharmacy Shipping To Ky,

张荣华 wrote 31天重构指南之三十一:使用多态代码条件判断
on 11-06-2009 3:53 AM

31天重构指南的最后一个重构来自于Fowlers的重构目录,你可以在这里查看。 这里展示了面向对象编程的基础之一“多态性”, 有时你需要检查对象的类型,并根据类型进行一些操作,在这种情况下将算法封装到...

Doctorset wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 11-20-2009 10:21 AM

This is the welcome page for the dentaldoctor.us Association web site.

Dietroly wrote re: Refactoring Day 31 : Replace conditional with Polymorphism
on 11-20-2009 11:02 PM

This is the welcome page for the dietguidance.us Association web site.

PetterLiu wrote 31 Days of Refactoring
on 11-27-2009 4:02 AM

Refactoring Day 1 : Encapsulate Collection Refactoring Day 2 : Move Method Refactoring Day 3 : Pull ...

PetterLiu wrote 31 Days of Refactoring
on 11-27-2009 4:04 AM

Refactoring Day 1 : Encapsulate Collection Refactoring Day 2 : Move Method Refactoring Day 3 : Pull ...

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright Los Techies 2008, 2009. All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems