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.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Sean Chambers

I am a Senior software developer from Palm Coast, Florida. An advocate of Domain Driven Design, Behavior Driven Development, creator of FluentMigrator and community activist. I am married to my beautiful wife Erin and am the proud father of two wonderful children. I currently reside at ACI, a local insurance industry/mortgage software company that excels in creating solutions using Agile methodologies.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Jordi

    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.

  • http://www.lostechies.com/members/schambers/default.aspx schambers

    @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.

  • http://fasudblog.freewhost.com/sitemap.html Samoys

    lot about you

  • http://blogs.ibibo.com/phentermine/buy-phentermine Roberto

    cool blog

  • http://vokiciy.angelfire.com dilandinga

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

  • http://gospensblog.go.ohost.de/ds/is-cialis-a-controlled-substance.html Frilith

    Great site. Keep doing.,

  • http://laskolblog.la.ohost.de/ms/xanax-doctors-in-dall-ft-worth.html Kalinwanpu

    Very cute :-) ))),

  • http://ibuprofen.idoo.com/free-levitra-trial.html Laulith

    Perfect work!,

  • http://global.idoo.com/soma-online-prescription-drug-ranch.html Nawia

    Very cute :-) ))),

  • http://aquafold.angelfire.com/soma-budget-medicines.html Kaiarith

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

  • http://dentaldoctor.us Doctorset

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

  • http://dietguidance.us Dietroly

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