原始代碼:
Customer類
package char1.version01;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
private String _name;
private Vector _rentals = new Vector<>();
public Customer(String _name) {
this._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 thisAmout = 0;
Rental each = (Rental) rentals.nextElement();
//
switch (each.get_movie().getPriceCode()) {
case Movie.REGULAR:
thisAmout += 2;
if (each.getDaysRented() > 2) {
thisAmout += (each.getDaysRented() - 2) * 1.5;
}
break;
case Movie.NEW_RELEASE:
thisAmout += each.getDaysRented() * 3;
break;
case Movie.CHILDRENS:
thisAmout += 1.5;
if (each.getDaysRented() > 3) {
thisAmout += (each.getDaysRented() - 3) * 1.5;
}
break;
}
// 加積分
frequentRenterPoints++;
//
if ((each.get_movie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) {
frequentRenterPoints++;
}
result += " " + each.get_movie().getTitle() + "\t" + String.valueOf(thisAmout) + "\n";
totalAmount += thisAmout;
}
// footer lines
result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
result += "You earned " + String.valueOf(frequentRenterPoints) + " frequent renter points";
return result;
}
}
Movie 類
package char1.version01;
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;
// 構(gòu)造函數(shù)
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;
}
}
Rental 類
package char1.version01;
public class Rental {
private Movie _movie;
private int _daysRented;
public Rental(Movie _movie, int _daysRented) {
this._movie = _movie;
this._daysRented = _daysRented;
}
public Movie get_movie() {
return _movie;
}
public Rental set_movie(Movie _movie) {
this._movie = _movie;
return this;
}
public int getDaysRented() {
return _daysRented;
}
public Rental setDaysRented(int _daysRented) {
this._daysRented = _daysRented;
return this;
}
}
測(cè)試類:
package char1.version01;
public class Test {
public static void main(String[] args) {
Customer c = new Customer("zhangs");
// 常規(guī)0 兒童2 新1
Movie movie0 = new Movie("Love",0);
Movie movie1 = new Movie("NEW",1);
Movie movie2 = new Movie("CHILD",2);
Rental rental1 = new Rental(movie0,4);
Rental rental2 = new Rental(movie1,5);
Rental rental3 = new Rental(movie2,6);
c.addRental(rental1);
c.addRental(rental2);
c.addRental(rental3);
System.out.println(c.getName());
System.out.println(c.statement());
}
}
重構(gòu)后的代碼
Customer 類
package char1.version04;
import java.util.Enumeration;
import java.util.Vector;
public class Customer {
private String _name;
private Vector _rentals = new Vector<>();
public Customer(String _name) {
this._name = _name;
}
public void addRental(Rental arg) {
_rentals.addElement(arg);
}
public String getName() {
return _name;
}
public String statement() {
Enumeration rentals = _rentals.elements();
String result = "Rental Record for" + getName() + "\n";
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += " " + each.get_movie().getTitle() + "\t" + each.getCharge() + "\n";
}
result += "Amount owed is " + getTotalCharge() + "\n";
result += "You earned " + 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;
}
}
Movie 類
package char1.version04;
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;
private Price _price;
public Movie(String title, int priceCode) {
_title = title;
setPriceCode(priceCode);
}
public int getPriceCode() {
return _price.getPriceCode();
}
public void setPriceCode(int arg) {
switch (arg) {
case REGULAR:
_price = new RegularPrice();
break;
case CHILDRENS:
_price = new ChildrenPrice();
break;
case NEW_RELEASE:
_price = new NewReleasePrice();
break;
default:
throw new IllegalArgumentException("Incorrect Price Code");
}
}
public String getTitle() {
return _title;
}
double getCharge(int dayRented) {
return _price.getCharge(dayRented);
}
int getFrequentRenterPoints(int daysRented) {
return _price.getFrequentRenterPoints(daysRented);
}
}
Price 類
package char1.version04;
abstract class Price {
abstract int getPriceCode();
abstract double getCharge(int dayRented);
int getFrequentRenterPoints(int daysRented) {
return 1;
}
}
class ChildrenPrice extends Price {
int getPriceCode() {
return Movie.CHILDRENS;
}
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3) {
result += (daysRented - 3) * 1.5;
}
return result;
}
}
class NewReleasePrice extends Price {
int getPriceCode() {
return Movie.NEW_RELEASE;
}
double getCharge(int daysRented) {
return daysRented * 3;
}
int getFrequentRenterPoints(int daysRented) {
return daysRented > 2 ? 2 : 1;
}
}
class RegularPrice extends Price {
int getPriceCode() {
return Movie.REGULAR;
}
double getCharge(int daysRented) {
double result = 2;
if (daysRented > 2) {
result += (daysRented - 2) * 1.5;
}
return result;
}
}
Rental 類
package char1.version04;
public class Rental {
private Movie _movie;
private int _daysRented;
public Rental(Movie _movie, int _daysRented) {
this._movie = _movie;
this._daysRented = _daysRented;
}
public Movie get_movie() {
return _movie;
}
public Rental set_movie(Movie _movie) {
this._movie = _movie;
return this;
}
public int getDaysRented() {
return _daysRented;
}
public Rental setDaysRented(int _daysRented) {
this._daysRented = _daysRented;
return this;
}
double getCharge() {
return _movie.getCharge(_daysRented);
}
int getFrequentRenterPoints() {
return _movie.getFrequentRenterPoints(_daysRented);
}
}
測(cè)試類不用改蒂秘。
如果你發(fā)現(xiàn)自己需要為程序添加一個(gè)新特性,而代碼結(jié)構(gòu)使你無法很方便地達(dá)成目的,那就先重構(gòu)那個(gè)程序裆悄,使特性的添加比較容易囱井,然后再添加特性蝉娜。
重構(gòu)前馏予,先檢查自己是否有一套可靠的測(cè)試機(jī)制乐尊。這些測(cè)試必須有自我檢驗(yàn)的能力雳刺。
重構(gòu)技術(shù)就是以微小的步伐修改程序劫灶,如果你犯下錯(cuò)誤,很容易便可以發(fā)現(xiàn)它掖桦。
任何一個(gè)傻瓜都能寫出計(jì)算機(jī)可以理解的代碼本昏。唯有寫出人類容易理解的代碼,才是優(yōu)秀的程序員枪汪。
(把自己的理解嵌入代碼中涌穆,這樣才不會(huì)遺忘我曾經(jīng)理解的東西)
這個(gè)例子中用到的重構(gòu)方法:
- Extract Method 提取方法
- Move Method 移動(dòng)方法
- Replace Conditional With Polymorphism 用多態(tài)替代條件表達(dá)式
- Replace Type Code with State/Strategy 用狀態(tài)/策略設(shè)計(jì)模式代替類型代碼
- Replace Temp with Query 用查詢替換臨時(shí)變量
- ……