重构前
代码一(Customer)
package cn.mr8god.refactoring;
import java.util.Enumeration;
import java.util.Vector;
/**
 * @author Mr8god
 * @date 2020/4/12
 * @time 00:29
 */
public class Customer {
    private String _name;
    private Vector _rentals = new Vector();
    public Customer(String name){
        _name = name;
    }
    public void addRental(Rental arg){
        _rentals.addElement(arg);
    }
    public String getName(){
        return _name;
    }
    public String statement(){
        double totalAmount = 0;
        int frequentRenterPoints = 0;
        Enumeration rentals = _rentals.elements();
        String result = "Rental Record for " + getName() + "\n";
        while (rentals.hasMoreElements()){
            double thisAmount = 0;
            Rental each = (Rental) rentals.nextElement();
            switch (each.getMovie().getPriceCode()){
                case Movie.REGULAR:
                    thisAmount += 2;
                    if (each.getDaysRented() > 2) {
                        thisAmount += (each.getDaysRented() -2) * 1.5;
                    }
                    break;
                case Movie.NEW_RELEASE:
                    thisAmount += each.getDaysRented() * 3;
                    break;
                case Movie.CHILDRENS:
                    thisAmount += 1.5;
                    if (each.getDaysRented() > 3) {
                        thisAmount += (each.getDaysRented() - 3) * 1.5;
                    }
                    break;
            }
            frequentRenterPoints ++;
            if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {
                frequentRenterPoints ++;
            }
            result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(thisAmount) + "\n";
            totalAmount += thisAmount;
        }
        result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
        result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";
        return result;
    }
}
代码二(Rental)
package cn.mr8god.refactoring;
/**
 * @author Mr8god
 * @date 2020/4/12
 * @time 00:14
 */
public class Rental {
    private Movie _movie;
    private int _daysRented;
    public Rental(Movie movie, int daysRented){
        _movie = movie;
        _daysRented = daysRented;
    }
    public int getDaysRented(){
        return _daysRented;
    }
    public Movie getMovie(){
        return _movie;
    }
}
代码三(Movie)
package cn.mr8god.refactoring;
/**
 * @author Mr8god
 * @date 2020/4/12
 * @time 00:01
 */
public class Movie {
    public static final int CHILDRENS = 2;
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    private String _title;
    private int _priceCode;
    public Movie(String title, int priceCode){
        _title = title;
        _priceCode = priceCode;
    }
    public int getPriceCode(){
        return _priceCode;
    }
    public void setPriceCode(int arg){
        _priceCode = arg;
    }
    public String getTitle(){
        return _title;
    }
}
第一次重构后
代码一(Customer)
package cn.mr8god.refactoring;
import java.util.Enumeration;
import java.util.Vector;
/**
 * @author Mr8god
 * @date 2020/4/12
 * @time 00:29
 */
public class Customer {
    private static String _name;
    private static Vector _rentals = new Vector();
    public Customer(String name){
        _name = name;
    }
    public void addRental(Rental arg){
        _rentals.addElement(arg);
    }
    public static String getName(){
        return _name;
    }
    public static String statement(){
        Enumeration rentals = _rentals.elements();
        String result = "Rental Record for " + getName() + "\n";
        while (rentals.hasMoreElements()){
            Rental each = (Rental) rentals.nextElement();
            result += "\t" + each.getMovie().getTitle() + "\t" + String.valueOf(each.getCharge()) + "\n";
        }
        result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";
        result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) + " frequent renter points";
        return result;
    }
    private double amountFor(Rental aRental){
        return aRental.getCharge();
    }
    private static double getTotalCharge(){
        double result = 0;
        Enumeration rentals = _rentals.elements();
        while (rentals.hasMoreElements()){
            Rental each = (Rental)rentals.nextElement();
            result += each.getCharge();
        }
        return result;
    }
    private static int getTotalFrequentRenterPoints(){
        int result = 0;
        Enumeration rentals = _rentals.elements();
        while (rentals.hasMoreElements()){
            Rental each = (Rental) rentals.nextElement();
            result += each.getFrequentRenterPoints();
        }
        return result;
    }
}
代码二(Rental)
package cn.mr8god.refactoring;
/**
 * @author Mr8god
 * @date 2020/4/12
 * @time 00:01
 */
public class Rental {
    private Movie _movie;
    private int _daysRented;
    public Rental(Movie movie, int daysRented){
        _movie = movie;
        _daysRented = daysRented;
    }
    public int getDaysRented(){
        return _daysRented;
    }
    public Movie getMovie(){
        return _movie;
    }
    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;
            default:
                throw new IllegalStateException("Unexpected value: " + getMovie().getPriceCode());
        }
        return result;
    }
    int getFrequentRenterPoints(){
        if ((getMovie().getPriceCode() == Movie.NEW_RELEASE) && getDaysRented() > 1){
            return 2;
        }else{
            return 1;
        }
    }
}
代码三(Movie)
package cn.mr8god.refactoring;
/**
 * @author Mr8god
 * @date 2020/4/12
 * @time 00:01
 */
public class Movie {
    public static final int CHILDRENS = 2;
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;
    private String _title;
    private int _priceCode;
    public Movie(String title, int priceCode){
        _title = title;
        _priceCode = priceCode;
    }
    public int getPriceCode(){
        return _priceCode;
    }
    public void setPriceCode(int arg){
        _priceCode = arg;
    }
    public String getTitle(){
        return _title;
    }
}
第一次重构心得
大多数重构都会减少代码量,但这次我们的重构却增加了代码量。
主要原因 这边使用的Java设置了大量语句来实现了一个累加循环。哪怕只是一个简单的累加循环,每个元素只需要一行代码,外围的支持代码也需要六行!虽然这是每个Java程序员都熟悉的写法,但是代码量还是太多了。
与其如此还不如不做这么多操作呢。再来说一下代码性能问题。原本代码只需要执行while循环一次就行了,经过我第一次重构后,代码居然要执行三次。进而代码的耗时可能就会很多,就可能大大降低了程序的性能。但是呢,这些本应不是我重构需要关心的问题,因为我其实本不知道我的代码经过一次重构后的性能会如何(害,说到这个我就想起了我的JProfiler,我现在还没能掌握它,难受),这需要专业的代码性能工具来进行测试。再说了,关于代码的性能,我们可以到后期进行性能优化时再考虑嘛。所以还没到最后呢!我们没有必要过早作出判决呀!
那么现在我们说一下优点哈。Now,Customer类内的所有代码都可以调用这些查询函数(就是我之前将临时变量浓缩成的那几个函数)。如果系统其它部分需要这部分信息,也可以轻松地将查询函数加入Customer类接口中。如果没有这些查询函数,其他函数就必须了解Rental类,并自行建立循环,这势必会增大程序的编写难度和维护难度。从而提高代码出错的概率。
好了好了,我们不能仅限于此哈,现在假设我们的产品经理又要跟我们提需求了,他们想让我们增加一个修改影片分类规则的功能。但是呢有没有具体告诉我们这究竟是一个怎样的分类规则。我们尚未清楚他们想怎么做,只知道新的分类法很快就要引入了。现有的分类法马上就要变了。与之相应的部分就是我们的计算方式和常客积分计算。我们现在必须要进入我们的计算方法和常客积分中,把因条件而异的代码替换掉,这样才能为将来的改变换上一层保护膜。我们开始新一轮的重构了!