jose luis gonzalez clua jose luis gonzalez clua - 3 months ago 10
Java Question

How can I refactor a JAVA method that returns a nested MAP?

public Map<product, SortedMap<Date, ServiceInterval>> getServiceInterval(
Contract pContract, BillCycle pBillCycle)
{
Map<product, SortedMap<Date, ServiceInterval>> returnMap = new HashMap<>();

List<product> productList = getAllproducts(pContract);

for (product product : productList)
{
Date billingDate = getBillingDate(product);

createReturnMap(
product, returnMap,
billingDate, pBillCycle);
}

return returnMap;
}


I was asked to refactor this method (simplified here) because:

Such complex type should not be used in interfaces.
Besides it makes the code difficult to debug.
The implementation should be hidden in the class.


I am not sure it makes sense to refactor this.

Do you agree that is worth refactoring this method?

If yes, what approach would you use? How can one make this easier for debugging?

Thanks

Answer
public Map<Product, SortedMap<Date, ServiceInterval>> getServiceInterval(
            Contract pContract, BillCycle pBillCycle)

Such complex type should not be used in interfaces. Besides it makes the code difficult to debug. The implementation should be hidden in the class.

I agree. If the service is provided to another client class, it may be cumbersome to use the returned object which is a map of map. So, you could use wrapper for your maps by providing a basic way for client classes to retrieve a ServiceInterval instance matching to input parameters : so containing a getServiceInterval() method in the returned object : public ServiceInterval getServiceInterval (Product product, Date date)
I propose product and date as input parameter as it's how you set your map of map :

Map<Product, SortedMap<Date, ServiceInterval>>

It's pseudo code written on the fly, just to show the idea:

public ServiceIntervalByProduct getServiceInterval(
        Contract pContract, BillCycle pBillCycle)  {
    ServiceIntervalByProduct  returnMap = new ServiceIntervalByProduct();

    List<product> productList = getAllproducts(pContract);

    for (product product : productList)
    {
        Date billingDate = getBillingDate(product);

        createReturnMap(
                product, returnMap,
                billingDate, pBillCycle);
    }

    return returnMap;
}

// First level Wrapper class
public class ServiceIntervalsByProduct{

  private Map<Product, ServiceIntervalsByDate>> mapByProduct;   

  public void add(Product product, Date date, ServiceInterval serviceInterval) {
   // add in inner map
  }

 public ServiceInterval getServiceInterval (Product product, Date date){
   // get from inner map
    return mapByProduct.get(product).getServiceInterval (date);    
 }
}


// Second level Wrapper class
public class ServiceIntervalsByDate{
  private  SortedMap<Date, ServiceInterval>> mapByDate;

  public void add(Date date, ServiceInterval serviceInterval){
   // add in inner map    
  }

  public ServiceInterval getServiceInterval (Date date){
   // get from inner map
    return mapByDate.get(date);
   }

}

I provide add() methods in the wrappers but you can gather all needed data in a constructor if you want to protect data modifications from client classes.

Comments