首先我们看重构之前的,共有三个类,Customer,Movie,Rental。全都是自己写的数据类。
// Rental: 表示某个顾客租了一部影片
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: 纯数据类,代表一个影片
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 priceCode)
{
_priceCode = priceCode;
}
public String getTitle()
{
return _title;
}
}
// Customer: 顾客
public class Customer
{
private String _name;
private Vector<Rental> _rentals = new Vector<Rental>();
public Customer(String name)
{
_name = name;
}
public void addRental(Rental rental)
{
_rentals.add(rental);
}
public String getName()
{
return _name;
}
public String statement()
{
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration<Rental> rentals = _rentals.elements();
String result = "Rental record for " + getName() + "\n";
while(rentals.hasMoreElements())
{
double thisAmount = 0;
Rental each = rentals.nextElement();
// determine amounts for each line
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;
}
// add frequent renter points
frequentRenterPoints++;
// add bonus for a two day new release rental
if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)
&& each.getDaysRented() > 1)
{
frequentRenterPoints++;
}
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ thisAmount + "\n";
totalAmount += thisAmount;
}
// add footer lines
result += "Amount owed is" + totalAmount + "\n";
result += "You earned " + frequentRenterPoints + "frequent renter points";
return result;
}
}
我们可以看到,Customer中的statement()函数过于复杂,这时我们就开始想要重构了。
首先我们看到,很明显的就是statement()中的switch语句,我们应该把它放到单独的一个函数中,所以我们要对switch处进行重构。
第一次重构:提取函数后的Customer类
// Customer: 顾客
public class Customer
{
private String _name;
private Vector<Rental> _rentals = new Vector<Rental>();
public Customer(String name)
{
_name = name;
}
public void addRental(Rental rental)
{
_rentals.add(rental);
}
public String getName()
{
return _name;
}
public String statement()
{
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration<Rental> rentals = _rentals.elements();
String result = "Rental record for " + getName() + "\n";
while(rentals.hasMoreElements())
{
double thisAmount = 0;
Rental each = rentals.nextElement();
thisAmount += amountFor(each);
// add frequent renter points
frequentRenterPoints++;
// add bonus for a two day new release rental
if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)
&& each.getDaysRented() > 1)
{
frequentRenterPoints++;
}
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ thisAmount + "\n";
totalAmount += thisAmount;
}
// add footer lines
result += "Amount owed is" + totalAmount + "\n";
result += "You earned " + frequentRenterPoints + "frequent renter points";
return result;
}
private double amountFor(Rental each)
{
double thisAmount = 0;
// determine amounts for each line
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;
}
return thisAmount;
}
}
之后我们会发现amountFor()中的一些变量的名字不是很好,所以我们进行重命名
private double amountFor(Rental aRental)
{
double result = 0;
// determine amounts for each line
switch(aRental.getMovie().getPriceCode())
{
case Movie.REGULAR:
result += 2;
if(aRental.getDaysRented() > 2)
{
result += (aRental.getDaysRented() - 2) * 1.5;
}
break;
case Movie.NEW_RELEASE:
result += aRental.getDaysRented() * 3;
break;
case Movie.CHILDRENS:
result += 1.5;
if(aRental.getDaysRented() > 3)
{
result += (aRental.getDaysRented() - 3) * 1.5;
}
break;
}
return result;
}
之后我们发现,amountFor()在Customer类中,可是却没有使用来自Customer类的信息,而是使用了来自Rental类的信息,所以我们需要考虑将amountFor()搬移到Rental类中
在这里我们同时改了一下函数名:amountFor() -> getCharge()
新的Rental:
// Rental: 表示某个顾客租了一部影片
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;
}
public double getCharge()
{
double result = 0;
// determine amounts for each line
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;
}
}
新的Customer中的statement:
public String statement()
{
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration<Rental> rentals = _rentals.elements();
String result = "Rental record for " + getName() + "\n";
while(rentals.hasMoreElements())
{
double thisAmount = 0;
Rental each = rentals.nextElement();
thisAmount += each.getCharge();
// add frequent renter points
frequentRenterPoints++;
// add bonus for a two day new release rental
if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)
&& each.getDaysRented() > 1)
{
frequentRenterPoints++;
}
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ thisAmount + "\n";
totalAmount += thisAmount;
}
// add footer lines
result += "Amount owed is" + totalAmount + "\n";
result += "You earned " + frequentRenterPoints + "frequent renter points";
return result;
}
之后我们发现,stateme()中的thisAmount显得有点多余了,接受each.getCharge()的执行结果,然后就不会有任何修改,所以我们运用Replace Temp With Query把thisAmount去掉
新的statement():
public String statement()
{
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration<Rental> rentals = _rentals.elements();
String result = "Rental record for " + getName() + "\n";
while(rentals.hasMoreElements())
{
Rental each = rentals.nextElement();
// add frequent renter points
frequentRenterPoints++;
// add bonus for a two day new release rental
if((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)
&& each.getDaysRented() > 1)
{
frequentRenterPoints++;
}
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ each.getCharge() + "\n";
totalAmount += each.getCharge();
}
// add footer lines
result += "Amount owed is" + totalAmount + "\n";
result += "You earned " + frequentRenterPoints + "frequent renter points";
return result;
}
下一步对“常客积分计算”做类似的处理,积分的计算视影片的种类而有所不同不过不像收费规则(getCharge())有那么多变化,我们将常客积分计算的任务交给Rental:
Rental中新增加的函数:
public int getFrequentRentalPoints()
{
int frequentRenterPoints = 0;
frequentRenterPoints++;
if(getMovie().getPriceCode() == Movie.NEW_RELEASE
&& getDaysRented() > 1)
{
frequentRenterPoints++;
}
return frequentRenterPoints;
}
Customer的statement函数:
public String statement()
{
double totalAmount = 0;
int frequentRenterPoints = 0;
Enumeration<Rental> rentals = _rentals.elements();
String result = "Rental record for " + getName() + "\n";
while(rentals.hasMoreElements())
{
Rental each = rentals.nextElement();
frequentRenterPoints += each.getFrequentRentalPoints();
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ each.getCharge() + "\n";
totalAmount += each.getCharge();
}
// add footer lines
result += "Amount owed is" + totalAmount + "\n";
result += "You earned " + frequentRenterPoints + "frequent renter points";
return result;
}
之后我们需要去除临时变量:
Customer中的statement函数以及新增加的getTotalCharge和getTotalFrequentRenterPoints函数
public String statement()
{
Enumeration<Rental> rentals = _rentals.elements();
String result = "Rental record for " + getName() + "\n";
while(rentals.hasMoreElements())
{
Rental each = rentals.nextElement();
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t"
+ each.getCharge() + "\n";
}
// add footer lines
result += "Amount owed is" + getTotalCharge() + "\n";
result += "You earned " + getTotalFrequentRenterPoints() + "frequent renter points";
return result;
}
private int getTotalFrequentRenterPoints()
{
int result = 0;
for(int n=0; n<_rentals.size(); n++)
{
result += _rentals.get(n).getFrequentRentalPoints();
}
return result;
}
private double getTotalCharge()
{
double result = 0;
for(int n=0; n<_rentals.size(); n++)
{
result += _rentals.get(n).getCharge();
}
return result;
}