您的位置:首页 > 编程语言

重构--改善既有代码的设计--读书笔记1

2011-01-31 17:07 381 查看

重构--改善既有代码的设计--读书笔记1

看了第一章的,敲出了所有的代码,共4版,自己理解写的比较少。以后慢慢在以后各章中补充吧。第一章看的还算顺利,可能代码太少了,还体会不深。

ver1
package Refactoring_Impr;

import java.util.Enumeration;
import java.util.Vector;

public class C1_ver1 {
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;
};
}

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;
}
}

class Customer {
private String _name;
private Vector<Rental> _rentals = new Vector<Rental>();

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<Rental> rentals = _rentals.elements();
String result = "Rental Record for " + getName() + "/n";
while (rentals.hasMoreElements()) {
double thisAmount = 0;
Rental each = (Rental) 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"
+ String.valueOf(thisAmount) + "/n";
totalAmount += thisAmount;

}
// add footer lines
result += "Amount owed is " + String.valueOf(totalAmount) + "/n";
result += "You earned " + String.valueOf(frequentRenterPoints)
+ " frequent renter points";
return result;
}
}
}

提取出accountFor()

拿到第一版本的代码,首先第一印象是statement()函数太长了。将长函数切分为几个短函数,当有新的功能函数需要实现时更好重用。
运用Extract Method提取switch代码段。
在大函数里面的局部变量,不会被修改的可以作为新的小函数的入参。

重构技术以微小的步伐前进,方便查错。

accountFor()移到到Rental类中,因为他只用到了Rental中的信息。
使用了委托测试新修改后的代码。

移去原有的多余临时变量thisAccount,改成rental.getCharge(),这涉及到了重构与性能的问题。(P69会再讨论) Replace temp with query

提取常客积点代码
点数计算的方式只与影片的类型有关。变化不会很多,先放到Rental中。
ver2
package Refactoring_Impr;

import java.util.Enumeration;
import java.util.Vector;

public class C1_ver2 {
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;
};
}

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 int getFrequentRenterPoints() {
if ((getMovie().getPriceCode() == Movie.NEW_RELEASE)
&& getDaysRented() > 1)
return 2;
else
return 1;
}

public 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;
}
return result;
}
}

class Customer {
private String _name;
private Vector<Rental> _rentals = new Vector<Rental>();

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<Rental> rentals = _rentals.elements();
String result = "Rental Record for " + getName() + "/n";
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
frequentRenterPoints += each.getFrequentRenterPoints();

// show figures for this rental
result += "/t" + each.getMovie().getTitle() + "/t"
+ String.valueOf(each.getCharge()) + "/n";
totalAmount += each.getCharge();
}

// add footer lines
result += "Amount owed is " + String.valueOf(totalAmount) + "/n";
result += "You earned " + String.valueOf(frequentRenterPoints)
+ " frequent renter points";
return result;
}
}

}

去除临时变量,totalAmountfrequentRenterPoints这两个临时变量
这样多带来了2次循环,但是提取成函数可以增加复用性。有利有弊
增加了一个htmlStatement()函数证明这点

多态取代switch
null
ver3
package Refactoring_Impr;

import java.util.Enumeration;
import java.util.Vector;

public class C1_ver3 {
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 String getTitle() {
return _title;
}

public int getFrequentRenterPoints(int daysRented) {
if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
return 2;
else
return 1;
}

double getCharge(int daysRented) {
double result = 0;
switch (getPriceCode()) {
case Movie.REGULAR:
result += 2;
if (daysRented > 2)
result += (daysRented - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
result += daysRented * 3;
break;
case Movie.CHILDRENS:
result += 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
break;
}
return result;
}
}

class Rental {
private Movie _movie;
private int _daysRented;

public Rental(Movie movie, int daysRented) {
_movie = movie;
_daysRented = daysRented;
}

public Movie getMovie() {
return _movie;
}

public int getFrequentRenterPoints() {
return _movie.getFrequentRenterPoints(_daysRented);
}

public double getCharge() {
return _movie.getCharge(_daysRented);
}
}

class Customer {
private String _name;
private Vector<Rental> _rentals = new Vector<Rental>();

public Customer(String name) {
_name = name;
};

public void addRental(Rental arg) {
_rentals.addElement(arg);
}

public String getName() {
return _name;
}

public String statement() {
Enumeration<Rental> 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;
}

public String htmlStatement() {
Enumeration<Rental> rentals = _rentals.elements();
String result = "<H1>Rentals for <EM>" + getName()
+ "</EM></H1><P>/n";
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
// show figures for each rental
result += each.getMovie().getTitle() + ": "
+ String.valueOf(each.getCharge()) + "<BR>/n";
}
// add footer lines
result += "<P>You owe <EM>" + String.valueOf(getTotalCharge())
+ "</EM><P>/n";
result += "On this rental you earned <EM>"
+ String.valueOf(getTotalFrequentRenterPoints())
+ "</EM> frequent renter points<P>";
return result;
}

private double getTotalCharge() {
double result = 0;
Enumeration<Rental> rentals = _rentals.elements();
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += each.getCharge();
}
return result;
}

private int getTotalFrequentRenterPoints() {
int result = 0;
Enumeration<Rental> rentals = _rentals.elements();
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
result += each.getFrequentRenterPoints();
}
return result;
}
}

}

继承
因为影片类型变化较大,且他们就好像在回答一种问题。采用继承体系。
ver4
package Refactoring_Impr;

import java.util.Enumeration;
import java.util.Vector;

import Refactoring_Impr.C1_ver2.Rental;

public class C1_ver4 {
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 Price _price;

public Movie(String title, int priceCode) {
_title = title;
setPriceCode(priceCode);
}

public double getCharge(int daysRented) {
return _price.getCharge(daysRented);
}

int getFrequentRenterPoints(int daysRented) {
return _price.getFrequentRenterPoints(daysRented);
}

public void setPriceCode(int arg) {
switch (arg) {
case REGULAR:
_price = new RegularPrice();
break;
case CHILDRENS:
_price = new ChildrensPrice();
break;
case NEW_RELEASE:
_price = new NewReleasePrice();
break;
default:
throw new IllegalArgumentException("Incorrect Price Code");
}
}

public String getTitle() {
return _title;
};
}

abstract class Price {
abstract double getCharge(int daysRented);

int getFrequentRenterPoints(int daysRented) {
return 1;
}
}

class ChildrensPrice extends Price {
double getCharge(int daysRented) {
double result = 1.5;
if (daysRented > 3)
result += (daysRented - 3) * 1.5;
return result;
}
}

class NewReleasePrice extends Price {
double getCharge(int daysRented) {
return daysRented * 3;
}

int getFrequentRenterPoints(int daysRented) {
return (daysRented > 1) ? 2 : 1;
}
}

class RegularPrice extends Price {
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;
}

public int getFrequentRenterPoints() {
return _movie.getFrequentRenterPoints(_daysRented);
}

public double getCharge() {
return _movie.getCharge(_daysRented);
}
}

class Customer {
private String _name;
private Vector<Rental> _rentals = new Vector<Rental>();

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<Rental> rentals = _rentals.elements();
String result = "Rental Record for " + getName() + "/n";
while (rentals.hasMoreElements()) {
Rental each = (Rental) rentals.nextElement();
frequentRenterPoints += each.getFrequentRenterPoints();

// show figures for this rental
result += "/t" + each.getMovie().getTitle() + "/t"
+ String.valueOf(each.getCharge()) + "/n";
totalAmount += each.getCharge();
}

// add footer lines
result += "Amount owed is " + String.valueOf(totalAmount) + "/n";
result += "You earned " + String.valueOf(frequentRenterPoints)
+ " frequent renter points";
return result;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: