Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactoring class to get rid of switch case

Tags:

c#

Say I have a class like this for calculating the cost of travelling different distances with different modes of transportation:

public class TransportationCostCalculator {     public double DistanceToDestination { get; set; }      public decimal CostOfTravel(string transportMethod)     {         switch (transportMethod)         {             case "Bicycle":                 return (decimal)(DistanceToDestination * 1);             case "Bus":                 return (decimal)(DistanceToDestination * 2);             case "Car":                 return (decimal)(DistanceToDestination * 3);             default:                 throw new ArgumentOutOfRangeException();         }     } 

This is fine and all, but switch cases can be a nightmare to maintenance wise, and what if I want to use airplane or train later on? Then I have to change the above class. What alternative to a switch case could I use here and any hints to how?

I'm imagining using it in a console application like this which would be run from the command-line with arguments for what kind of transportation vehicle you want to use, and the distance you want to travel:

class Program {     static void Main(string[] args)     {         if(args.Length < 2)         {             Console.WriteLine("Not enough arguments to run this program");             Console.ReadLine();         }         else         {             var transportMethod = args[0];             var distance = args[1];             var calculator = new TransportCostCalculator { DistanceToDestination = double.Parse(distance) };             var result = calculator.CostOfTravel(transportMethod);             Console.WriteLine(result);             Console.ReadLine();         }     } } 

Any hints greatly appreciated!

like image 945
Khaine775 Avatar asked Feb 25 '16 13:02

Khaine775


People also ask

How do you refactor a switch?

Apply the Replace Type Code with Subclasses refactoring: Add subclasses for each type represented by the type code. Use a factory method to create the subclass objects based on the type. Apply Push Down Method by moving the switch-statement-abusing methods to the subclasses.

How do you not use a switch case?

The first and second options to avoid switch cases keep the original string array cardTypes . All other examples base on the conversion to a List<string> . This is only a short comparison of meaningful substitutions of a switch case.

Can we skip default in switch case?

No its not neccesary. the default case in switch statement is not necessary,but it is useful when no case in switch is satisified or not matched then automatically it executes the default statement,if it is not there ,the switch statement is terminated.


1 Answers

You could do something like this:

public class TransportationCostCalculator {     Dictionary<string,double> _travelModifier;      TransportationCostCalculator()     {         _travelModifier = new Dictionary<string,double> ();          _travelModifier.Add("bicycle", 1);         _travelModifier.Add("bus", 2);         _travelModifier.Add("car", 3);     }       public decimal CostOfTravel(string transportationMethod) =>        (decimal) _travelModifier[transportationMethod] * DistanceToDestination; } 

You could then load the transportation type and it's modifier in a configuration file instead of using a switch statement. I put it in the constructor to show the example, but it could be loaded from anywhere. I would also probably make the Dictionary static and only load it once. There is no need to keep populating it each time you create a new TransportationCostCalculator especially if it isn't going to change during runtime.

As noted above, here is how you could load it by a configuration file:

void Main() {   // By Hard coding.    /*     TransportationCostCalculator.AddTravelModifier("bicycle", 1);     TransportationCostCalculator.AddTravelModifier("bus", 2);     TransportationCostCalculator.AddTravelModifier("car", 3);   */     //By File      //assuming file is: name,value     System.IO.File.ReadAllLines("C:\\temp\\modifiers.txt")     .ToList().ForEach(line =>         {            var parts = line.Split(',');         TransportationCostCalculator.AddTravelModifier             (parts[0], Double.Parse(parts[1]));         }     );  }  public class TransportationCostCalculator {     static Dictionary<string,double> _travelModifier =           new Dictionary<string,double> ();      public static void AddTravelModifier(string name, double modifier)     {         if (_travelModifier.ContainsKey(name))         {             throw new Exception($"{name} already exists in dictionary.");         }          _travelModifier.Add(name, modifier);     }      public double DistanceToDestination { get; set; }      TransportationCostCalculator()     {         _travelModifier = new Dictionary<string,double> ();     }       public decimal CostOfTravel(string transportationMethod) =>        (decimal)( _travelModifier[transportationMethod] * DistanceToDestination); } 

Edit: It was mentioned in the comments that this wouldn't allow the equation to be modified if it ever needed to change without updating the code, so I wrote up a post about how to do it here: http://structuredsight.com/2016/03/07/configuring-logic.

like image 57
kemiller2002 Avatar answered Oct 09 '22 23:10

kemiller2002