《重构 改善既有代码的设计》 读书笔记(四)

1.3.4 练习:重构常客积分计算
public String statement2() {
	double totalAmount = 0;
	int frequentRenterPoints = 0;
	Iterator<Rental> rentalIter = rentals.iterator();
	String result = "Rental Record for " + getName() + "\n";
	while (rentalIter.hasNext()) {
		double thisAmount = 0;
		Rental each = rentalIter.next();
		// determine amounts for each line(确定每行的金额)
		thisAmount = each.getCharge();
		// add frequent renter points(增加常客的积分)
		frequentRenterPoints++;
		// add bonus for a two day new release rental(为两天的新释放租金增加奖金)
		// 积分根据是否是新片有所不同
		if ((each.getMovie().getPriceCode() == Movie.NEWRELEASE)
				&& each.getDayRented() > 1)
			frequentRenterPoints++;
		// show figures for the rental(显示租金的数字)
		result += each.getMovie().getTitle() + "\t\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;
}

下面我们的关注点可以放在frequentRenterPoints这个变量上,好好思考一下应该怎么去重构这一部分。

  1. 提炼函数

    就像之前那样,找到局部变量与参数。

    很明显,each和frequentRenterPoints。

    所以我们可以提炼出一个新的函数:getFrequentRenterPoints()。

  2. 搬移函数

    就和之前一样,提炼出的方法和Customer没有什么关联,也需要放到Rental类中。

  3. 以查询取代临时变量

    注意!和之前不一样的是,每循环一次,frequentRenterPoints都是累加上一次的值,也就是说,它并不是一个‘常量’。此处我们可以直接把新函数的返回值累加上去即可。

下面是更改后的代码:

public String statement2() {
	double totalAmount = 0;
	int frequentRenterPoints = 0;
	Iterator<Rental> rentalIter = rentals.iterator();
	String result = "Rental Record for " + getName() + "\n";
	while (rentalIter.hasNext()) {
		Rental each = rentalIter.next();
		frequentRenterPoints += each.getFrequentRenterPoint();
		// show figures for the rental(显示租金的数字)
		result += each.getMovie().getTitle() + "\t\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;
}
//Rental类中的方法
/**
 * 计算常客积分
 *
 * @author newre
 * @return
 */
public int getFrequentRenterPoint() {
	int frequentRenterPoints = 0;
	frequentRenterPoints++;
	if ((this.getMovie().getPriceCode() == Movie.NEWRELEASE)
			&& this.getDayRented() > 1)
		frequentRenterPoints++;
	return frequentRenterPoints;
}

简化到了这里,getFrequentRenterPoint()其实还不够精炼——frequentRenterPoints太碍眼了,能不能去掉呢?

public int getFrequentRenterPoint() {
	if ((this.getMovie().getPriceCode() == Movie.NEWRELEASE)
			&& this.getDayRented() > 1)
		return 2;
	else
		return 1;
}

此时,类图又一次发生了更改

/'在线作图(UML)网址:
http://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000
如果要修改的的话,打开网址后,直接复制上图片链接(或者粘贴下方代码)修改即可'/
@startuml
Title "影片出租店程序"
class Movie{
- private int priceCode
}
class Rental{
- private int daysRented
+ public getCharge()
+ public getFrequentRenterPoint()
}
class Customer{
+ public statement()
}
Rental --> Movie
Customer --> Rental
@enduml

在这里插入图片描述

1.3.5 练习:去除临时变量

消灭临时变量本身并不困难,困难的是,你要克服自己的认知——去吧,把代码‘复杂化’。

这一次练习的目的,是消灭totalAmount和frequentRenterPoints,如果打破天窗来说,其实很容易,难的是想到这样的方法——

新建一个方法吧,在方法内去遍历。

public String statement2() {
	Iterator<Rental> rentalIter = rentals.iterator();
	String result = "Rental Record for " + getName() + "\n";
	while (rentalIter.hasNext()) {
		Rental each = rentalIter.next();
		// show figures for the rental(显示租金的数字)
		result += each.getMovie().getTitle() + "\t\t"
				+ String.valueOf(each.getCharge()) + "\n";
	}
	// add footer lines(添加页脚行)
	result += "Amount owed is " + String.valueOf(getTotalCharge(rentals)) + "\n";
	result += "You earned "
			+ String.valueOf(getTotalFrequentRenterPoints(rentals))
			+ " frequent renter points";
	return result;
}
/**
 * 获取总价
 *
 * @author newre
 * @param rentals
 * @return
 */
private double getTotalCharge(Vector<Rental> rentals) {
	double result = 0;
	Iterator<Rental> rentalIter = rentals.iterator();
	while (rentalIter.hasNext()) {
		Rental each = rentalIter.next();
		result += each.getCharge();
	}
	return result;
}
/**
 * 获取总积分
 *
 * @author newre
 * @param rentals
 * @return
 */
private int getTotalFrequentRenterPoints(Vector<Rental> rentals) {
	int result = 0;
	Iterator<Rental> rentalIter = rentals.iterator();
	while (rentalIter.hasNext()) {
		Rental each = rentalIter.next();
		result += each.getFrequentRenterPoint();
	}
	return result;
}

记住,每进行一步,都要进行测试,养成习惯。(如果一时半会养成不了也没关系,摔得次数多了,也就会了)

再看看此时的类图。

/'在线作图(UML)网址:
http://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000
如果要修改的的话,打开网址后,直接复制上图片链接(或者粘贴下方代码)修改即可'/
@startuml
Title "影片出租店程序"
class Movie{
- private int priceCode
}
class Rental{
- private int daysRented
+ public getCharge()
+ public getFrequentRenterPoint()
}
class Customer{
+ public statement()
+ private getTotal()
+ private getTotalFrequentRenterPoints()
}
Rental --> Movie
Customer --> Rental
@enduml

在这里插入图片描述

1.3.6 最后小结

此时,单论statement()这个方法,已经变得极为简单,看看其中的内容我们可以发现,里面只剩下了字符串的拼接,这也正是我们重构的目的——职能划分

回顾一下最开始的需求:
1、以HTML格式输出详单
在现在的代码结构下,我们仅需要新建一个方法,更改字符串拼接,至于里面方法逻辑,我们无需改动。
再看看第二个需求:
2、计费标准改变
amazing!我们只需更改Rental类中的getCharge()方法即可。
3、影片分类规则更改,具体改变方法据情况而定
a ha?情况而定?

现在,我们对statement()进行了重构,但显而易见的是,这样不够,不管是性能上,还是面对客户的需求上,我们还不能达到‘以不变应万变’的地步,我们只完成了第一个大步,剩余的路还需要走下去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NewReErWen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值