Refactor switch statement - using an object vs primitive data type

Eran Morad :

I am learning how to refactor Java code with the book Refactoring: Improving the Design of Existing Code (1st edition). The author does the refactoring shown below and gives an explanation for why he did it which is not clear to me. Can someone help me to understand the explanation? The code is for movie rental software.

public class Movie {

    //Lets call these constants "priceCode".
    public static final int  CHILDRENS = 2;
    public static final int  REGULAR = 0;
    public static final int  NEW_RELEASE = 1;

//...more code here...
}

class Rental {
    private Movie _movie;
    private int _daysRented;
//...more code here...
}

BEFORE REFACTORING:

class Rental...
   double getCharge() {
       double result = 0;
       switch (getMovie().getPriceCode()) {
           case Movie.REGULAR:
               result += 2;
               if (getDaysRented() > 2)
                   result += (getDaysRented() - 2) * 1.5;
               break;
           case Movie.NEW_RELEASE:
               result += getDaysRented() * 3;
               break;
           case Movie.CHILDRENS:
               result += 1.5;
               if (getDaysRented() > 3)
                   result += (getDaysRented() - 3) * 1.5;
               break;
       }
       return result;
  }

We move the above method code into the already existing Movie class.

AFTER REFACTORING:

 class Movie...
   double getCharge(int daysRented) {
       double result = 0;
       switch (getPriceCode()) {
           case Movie.REGULAR:
               result += 2;
               if (daysRented > 2)
                   result += (daysRented - 2) * 1.5;
               break;
           case Movie.NEW_RELEASE:
               result += daysRented * 3;
               break;
           case Movie.CHILDRENS:
               result += 1.5;
               if (daysRented > 3)
                   result += (daysRented - 3) * 1.5;
               break;
       }
       return result;
   }

AUTHOR'S EXPLANATION:

It is a bad idea to do a switch based on an attribute of another object. If you must use a switch statement, it should be on your own data, not on someone else’s.

For this, to work I had to pass in the length of the rental, which of course is data from the rental. The method effectively uses two pieces of data, the length of the rental and the type of the movie. Why do I prefer to pass the length of rental to the movie rather than the movie type to the rental? It’s because the proposed changes are all about adding new types. Type information generally tends to be more volatile. If I change the movie type, I want the least ripple effect, so I prefer to calculate the charge within the movie.

MY QUESTIONS:

Why is it a bad idea to do a switch based on an attribute of another object?

What do these things really mean "type info generally tends to be volatile" and "least ripple effect (is achieved)"? These vague words (volatile and ripple) don't clearly explain the advantage of this refactoring.

PS - Please note that this is not the final code. There is more refactoring later in the book. I know that this is an outdated 1990s book. Despite that, it looks like the book has plenty of ideas and concepts about designing code which could still be useful today. But, I am not sure how much help this book will be in 2020. Moreover, the latest version of the book, Refactoring: Improving the Design of Existing Code (2nd edition), uses Javascript which I don't know.

Ivan :

Why is it a bad idea to do a switch based on an attribute of another object?

Because if the type of that attribute is changed you have to make changes in your own code. If type of Movie.priceCode is switched from int to enum then you will also have to change code in Rental. But you you move price calculation to Movie than you can change type of Movie.priceCode without affecting Rental.

What do these things really mean "type info generally tends to be volatile" and "least ripple effect (is achieved)"? These vague words (volatile and ripple) don't clearly explain the advantage of this refactoring.

If you decide to add more price codes to a movie (like HBO series, Disney series, etc) then you will have to make changes in both Movie and Rental classes. But if you do not use Movie.priceCode inside Rental then you do not need to change Rental class at all even if you remove priceCode from movie or rename it or change its type. In this case refactoring help to localize scope of the change. Assume that you write code for Movie and another team writes code for Rental and you decided to add more price types. Now you need to notify that other team that you added more types, provide them values, logic for calculation, possibly build new artifact with new version of your Movie class. But if you only provide them method getCharge(daysRented) then you can add whatever new types without notification overhead.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=11932&siteId=1