Skip to main content

重构笔记

· 8 min read
CheverJohn

重构前

代码一(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类,并自行建立循环,这势必会增大程序的编写难度和维护难度。从而提高代码出错的概率。

好了好了,我们不能仅限于此哈,现在假设我们的产品经理又要跟我们提需求了,他们想让我们增加一个修改影片分类规则的功能。但是呢有没有具体告诉我们这究竟是一个怎样的分类规则。我们尚未清楚他们想怎么做,只知道新的分类法很快就要引入了。现有的分类法马上就要变了。与之相应的部分就是我们的计算方式和常客积分计算。我们现在必须要进入我们的计算方法和常客积分中,把因条件而异的代码替换掉,这样才能为将来的改变换上一层保护膜。我们开始新一轮的重构了!