对《重构-改善既有代码的设计》一书,对书中第一章的例子,利用JAVA语言完成该例子的代码重构。重构时,增量地给程序添加以下功能 (1) 增加新的影片分类,如纪录片、综艺片等 (2) 修改影片的租赁和积分标准 (3) 以HTML格式输出订单针对第二节分析出的现有代码问题,依据代码重构的原则与技巧,逐一给出重构(解决)方案(重构思路、采用方法与技巧(--35分)。总体表达方法可参考该书);
时间: 2023-12-03 13:45:42 浏览: 31
重构思路:
首先,需要对现有的代码进行分析,找出其中存在的问题。然后,采用重构的原则与技巧,逐一解决这些问题,并增量地添加新功能。最后,以HTML格式输出订单。
1. 问题分析:
现有的代码存在以下问题:
(1)`Movie`类中存在过多的if语句,导致代码难以维护和扩展。
(2)`Rental`类中计算租赁费用和积分的方法过于复杂,可读性差。
(3)`Customer`类中的`statement`方法过于复杂,可读性差,需要拆分为多个小方法。
2. 解决方案:
(1)重构`Movie`类:
将`Movie`类中的if语句替换为多态,即在`Movie`类中添加一个抽象方法`getCharge`,然后在三个子类`RegularMovie`、`NewReleaseMovie`和`ChildrensMovie`中分别实现该方法,计算相应的租赁费用。
```
abstract class Movie {
//...省略其他代码...
abstract double getCharge(int daysRented);
}
class RegularMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
return result;
}
}
class NewReleaseMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
return daysRented * 3;
}
}
class ChildrensMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}
```
(2)重构`Rental`类:
将`Rental`类中计算租赁费用和积分的方法拆分为两个方法,分别计算租赁费用和积分。同时,将计算租赁费用和积分的方法移动到`Movie`类中,由多态来实现。
```
class Rental {
//...省略其他代码...
double getCharge() {
return _movie.getCharge(_daysRented);
}
int getFrequentRenterPoints() {
// add bonus for a two day new release rental
if ((_movie instanceof NewReleaseMovie) && _daysRented > 1)
return 2;
else
return 1;
}
}
//在Movie类中添加getCharge方法
abstract class Movie {
//...省略其他代码...
abstract double getCharge(int daysRented);
}
class RegularMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
return result;
}
}
class NewReleaseMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
return daysRented * 3;
}
}
class ChildrensMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}
```
(3)重构`Customer`类:
将`Customer`类中的`statement`方法拆分为多个小方法,提高可读性。
```
class Customer {
//...省略其他代码...
String statement() {
Enumeration rentals = _rentals.elements();
String result = "Rental Record for " + getName() + "\n";
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
// show figures for this rental
result += "\t" + each.getMovie().getTitle() + "\t" +
String.valueOf(each.getCharge()) + "\n";
}
// add footer lines
result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";
result += "You earned " + String.valueOf(getTotalFrequentRenterPoints()) +
" frequent renter points";
return result;
}
private double getTotalCharge() {
double result = 0;
Enumeration rentals = _rentals.elements();
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += each.getCharge();
}
return result;
}
private int getTotalFrequentRenterPoints() {
int result = 0;
Enumeration rentals = _rentals.elements();
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += each.getFrequentRenterPoints();
}
return result;
}
}
```
(4)增加新的影片分类:
在`Movie`类中添加新的影片分类,如纪录片、综艺片等。具体实现方式与上述步骤类似,在`Movie`类中添加相应的子类,并重写`getCharge`方法。
```
class DocumentaryMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}
class VarietyShowMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
return result;
}
}
```
(5)修改影片的租赁和积分标准:
在`Rental`类中修改`getFrequentRenterPoints`方法和`Movie`类中相应子类的`getCharge`方法。
```
class Rental {
//...省略其他代码...
int getFrequentRenterPoints() {
// add bonus for a two day new release rental
if ((_movie instanceof NewReleaseMovie) && _daysRented > 1)
return 3; //租赁新片大于1天,积分加3
else
return 1;
}
}
class RegularMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 1.5; //修改租赁价格
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}
class ChildrensMovie extends Movie {
//...省略其他代码...
double getCharge(int daysRented) {
double result = 1.5; //修改租赁价格
if (daysRented > 4)
result += (daysRented - 4) * 1.5;
return result;
}
}
```
(6)以HTML格式输出订单:
重构`Customer`类中的`statement`方法,将订单信息按照HTML格式输出。
```
class Customer {
//...省略其他代码...
String statement() {
Enumeration rentals = _rentals.elements();
String result = "<h1>Rentals for " + getName() + "</h1><br/>";
result += "<table border='1'><tr><th>Movie Title</th><th>Rental Days</th><th>Price</th></tr>"; //添加表头
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
// show figures for this rental
result += "<tr><td>" + each.getMovie().getTitle() + "</td><td>" +
String.valueOf(each.getDaysRented()) + "</td><td>" + String.valueOf(each.getCharge()) + "</td></tr>";
}
// add footer lines
result += "</table><br/><h2>Amount owed is " + String.valueOf(getTotalCharge()) + "</h2>";
result += "<h2>You earned " + String.valueOf(getTotalFrequentRenterPoints()) +
" frequent renter points</h2>";
return result;
}
}
```
3. 代码重构:
重构后的完整代码如下:
```
abstract class Movie {
private String _title;
public Movie(String title) {
_title = title;
}
public String getTitle() {
return _title;
}
abstract double getCharge(int daysRented);
}
class RegularMovie extends Movie {
public RegularMovie(String title) {
super(title);
}
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}
class NewReleaseMovie extends Movie {
public NewReleaseMovie(String title) {
super(title);
}
double getCharge(int daysRented) {
return daysRented * 3;
}
}
class ChildrensMovie extends Movie {
public ChildrensMovie(String title) {
super(title);
}
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 4)
result += (daysRented - 4) * 1.5;
return result;
}
}
class DocumentaryMovie extends Movie {
public DocumentaryMovie(String title) {
super(title);
}
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}
class VarietyShowMovie extends Movie {
public VarietyShowMovie(String title) {
super(title);
}
double getCharge(int daysRented) {
double result = 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
return result;
}
}
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() {
return _movie.getCharge(_daysRented);
}
int getFrequentRenterPoints() {
// add bonus for a two day new release rental
if ((_movie instanceof NewReleaseMovie) && _daysRented > 1)
return 3;
else
return 1;
}
}
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;
}
String statement() {
Enumeration rentals = _rentals.elements();
String result = "<h1>Rentals for " + getName() + "</h1><br/>";
result += "<table border='1'><tr><th>Movie Title</th><th>Rental Days</th><th>Price</th></tr>";
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
// show figures for this rental
result += "<tr><td>" + each.getMovie().getTitle() + "</td><td>" +
String.valueOf(each.getDaysRented()) + "</td><td>" + String.valueOf(each.getCharge()) + "</td></tr>";
}
// add footer lines
result += "</table><br/><h2>Amount owed is " + String.valueOf(getTotalCharge()) + "</h2>";
result += "<h2>You earned " + String.valueOf(getTotalFrequentRenterPoints()) +
" frequent renter points</h2>";
return result;
}
private double getTotalCharge() {
double result = 0;
Enumeration rentals = _rentals.elements();
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += each.getCharge();
}
return result;
}
private int getTotalFrequentRenterPoints() {
int result = 0;
Enumeration rentals = _rentals.elements();
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += each.getFrequentRenterPoints();
}
return result;
}
}
```