Sunday, September 25, 2016

Refactoring if else-if and switch statement code block

I will show you how we can refactor an if else-if or switch case statement code block in more batter way.

Though I'm using C# language here but you can use this approach in other programming languages too.

Before Refactoring

Let's we have a switch statement code block in our application which returns the Excel file name depending on ExportType enum.
         public string GetReportFileName(ExportType exportType)
          {
              string fileName;
              switch (exportType)
              {
                  case ExportType.MemberDataVersioning:
                      fileName = "MemberList.xls";
                      break;
                  case ExportType.MemberProfileInformation:
                      fileName = "MemberProfile.xls";
                      break;
                  case ExportType.MemberOtherDataVersioningDetails:
                      fileName = "MemberRecords.xls";
                      break;
                  case ExportType.ProviderDataVersioning:
                      fileName = "ProviderList.xls";
                      break;
                  case ExportType.ProviderProfileInformation:
                      fileName = "ProviderProfile.xls";
                      break;
                  case ExportType.ProviderOtherDataVersioningDetails:
                      fileName = "ProviderRecords.xls";
                      break;
                  case ExportType.ClaimsDataVersioning:
                      fileName = "ClaimList.xls";
                      break;
                  case ExportType.ClaimsDataChangeLog:
                      fileName = "ClaimDataChangeLog.xls";
                      break;
                  case ExportType.ElementWiseValidationReport:
                      fileName = "ElementDetails.xls";
                      break;
                  case ExportType.ReconciliationReport:
                      fileName = "RecociliationReport.xls";
                      break;

                  default:
                      fileName = exportType.ToString() + ".xls";
                      break;
              }

              return fileName;
          }
                    
When a new export type will come then we have to add another switch case statement and will continue this process for every new export type.

After Refactoring

There is nice refactoring way which we can apply to improve the code quality and simplicity.
We can use a dictionary instead of the switch statement. Let's we declare a dictionary of report file types in constructor:
        private readonly Dictionary<ExportType, string> reportFileNames;
    
        public ReportFileHelper()
          {
              this.reportFileNames = new Dictionary<ExportType, string>
                                    {
                                        { ExportType.MemberDataVersioning, "MemberList.xls" },
                                        { ExportType.MemberProfileInformation, "MemberProfile.xls" },
                                        { ExportType.MemberOtherDataVersioningDetails, "MemberRecords.xls" },
                                        { ExportType.ProviderDataVersioning, "ProviderList.xls" },
                                        { ExportType.ProviderProfileInformation, "ProviderProfile.xls" },
                                        { ExportType.ProviderOtherDataVersioningDetails, "ProviderRecords.xls" },
                                        { ExportType.ClaimsDataVersioning, "ClaimList.xls" },
                                        { ExportType.ClaimsDataChangeLog, "ClaimChangeLog.xls" },
                                        { ExportType.ElementWiseValidationReport, "ElementDetails.xls" },
                                        { ExportType.ReconciliationReport, "RecociliationReport.xls" }
                                    };
          }
                    
Now we can easily refactore the GetReportFileName method with this simple lines of code:
         public string GetReportFileName(ExportType exportType)
          {
            string fileName; 
            return reportFileNames.TryGetValue(exportType, out fileName) ? fileName : (exportType.ToString() + ".xls");
          }
                    

When a new report type comes, we will just add an item in reportFileNames dictionary.

Similarly, we can also use this refactoring approach in the if else-if statement.

Before Refactoring

Let's we have a function which return a customer object based on customer type.

Here is the code block:

    public ICustomer GetCustomer(CustomerType customerType)
        {
            ICustomer customer = null;
            if (customerType == CustomerType.Gold)
            {
                customer = new GoldCustomer();
            }
            else if (customerType == CustomerType.Platinum)
            {
                customer = new PlatinumCustomer();
            }
            else if (customerType == CustomerType.Silver)
            {
                customer = new SilverCustomer();
            }
            else if (customerType == CustomerType.Normal)
            {
                customer = new NormalCustomer();
            }

            return customer;
        }
                    

After Refactoring

We will declare a dictionary in the constructor. Here I have used Func of the customer.

Func is a very nice feature in c#. you can get details from here.

        private readonly Dictionary<CustomerType, Func<ICustomer>> customerTypes;

        public CustomerFactory()
        {
            this.customerTypes = new Dictionary<CustomerType, Func<ICustomer>>
                      {
                          { CustomerType.Gold, () => new GoldCustomer() },
                          { CustomerType.Platinum, () => new PlatinumCustomer() },
                          { CustomerType.Silver, () => new SilverCustomer() },
                          { CustomerType.Normal, () => new NormalCustomer() },
                      };
        }
                    

Now we can replace the GetCustomer method in this way.

    public ICustomer GetCustomer(CustomerType customerType)
        {
            Func<ICustomer> customer;
            return this.customerTypes.TryGetValue(customerType, out customer) ? customer() : null;
        }
                    
Any feedbacks are most welcomed. If you know any better approach, please share it here.

1 comment:

  1. But what about performance? Do you check bench mark?

    ReplyDelete