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.