日期:2014-05-18 浏览次数:21105 次
上一篇使用了Extract Method技巧,从Statement方法中分离出了AmountFor方法,从而略微提高了Statement方法的可读性,下面我们继续跟着《重构》的脚步来进行剩余的重构。当然在继续之前,我还是会提醒你,每一步重构之后,记得运行单元测试,它是重构的基石。
一、重命名AmountFor的局部变量
首先看看我们先前抽取出来的AmountFor方法:
public double AmountFor(Rental rental)
{
	double thisAmount = 0;
	switch (rental.Movie.PriceCode)
	{
		case Movie.REGULAR:
			thisAmount += 2;
			if (rental.DaysRented > 2)
				thisAmount += (rental.DaysRented - 2) * 1.5;
			break;
		case Movie.NEW_RELEASE:
			thisAmount += rental.DaysRented * 3;
			break;
		case Movie.CHILDRENS:
			thisAmount += 1.5;
			if (rental.DaysRented > 3)
				thisAmount += (rental.DaysRented - 3) * 1.5;
			break;
	}
	return thisAmount;
}方法中有个局部变量:thisAmount,实际上,该名称是在Statement方法中起的。而对于AmountFor方法而言,只可能有一个amount,对应传参进来的rental。所以,加上this的修饰反而是画蛇添足的做法。而我也不太认同《重构》中对该局部变量的新命名(result),result一词过于宽泛,也有许多其它数据提到过这个问题,例如避免使用如result,item,manager,这一类“万能”词汇。所以,改进后的代码如下:private double AmountFor(Rental rental)
{
	double amount = 0;
	switch (rental.Movie.PriceCode)
	{
		case Movie.REGULAR:
			amount += 2;
			if (rental.DaysRented > 2)
				amount += (rental.DaysRented - 2) * 1.5;
			break;
		case Movie.NEW_RELEASE:
			amount += rental.DaysRented * 3;
			break;
		case Movie.CHILDRENS:
			amount += 1.5;
			if (rental.DaysRented > 3)
				amount += (rental.DaysRented - 3) * 1.5;
			break;
	} 
	
	return amount;
}如书上所言,不要忽视这种微小的重构,它的确能降低代码的理解难度。试想,如果一个朋友本想和你说“圣诞快乐”,却说成了“新年幸福”,这也许在西方国家并不存在太大问题,但是中国人却是难以将两件事情联系在一起的。所以,让你的命名确切地表示它的意思,这很重要。在我的编码工作中,甚至可能超过15%的时间是花在为类、方法、字段等内容的命名上,浪费吗?一点都不!
二、将AmountFor方法转移到Rental类
《重构》:目前的AmountFor没有使用任何Customer类的属性、字段、方法,它在不在Customer方法中其实并不是那么重要,而这正是暗示该方法不应该属于该类型的明确信号,Rental类才是它的归属地。下面是重构的过程:
1.在Rental类中创建一个Charge属性,并将AmountFor中的代码抄过去:
public double Charge
{
	get
	{
		double amount = 0;
		switch (Movie.PriceCode)
		{
			case Movie.REGULAR:
				amount += 2;
				if (DaysRented > 2)
					amount += (DaysRented - 2) * 1.5;
				break;
			case Movie.NEW_RELEASE:
				amount += DaysRented * 3;
				break;
			case Movie.CHILDRENS:
				amount += 1.5;
				if (DaysRented > 3)
					amount += (DaysRented - 3) * 1.5;
				break;
		}
		return amount;
	}
}
2.把原Customer的AmountFor方法体清空,但仍保留声明和空的函数体。        private double AmountFor(Rental rental)
        {
            return 0;
        }
3.更改Customer的AmountFor实现为:        private double AmountFor(Rental rental)
        {
            return rental.Charge;
        }4.运行测试项目,如果不通过,则检查、修改代码。直到通过为止public string Statement()
{
	double totalAmount = 0;
	int frequentRenterPoints = 0;
	string result = "Rental Record for " + Name + "\n";
	foreach (Rental rental in Rentals)
	{
		double thisAmount = rental.Charge;
		// add frequent renter points
		frequentRenterPoints++;
		// add bonus for a two day new release rental
		if (rental.Movie.PriceCode == Movie.NEW_RELEASE &&
			rental.DaysRented > 1) frequentRenterPoints++;
		
		// show figures for this rental
		result += "\t" + rental.Movie.Title + "\t" + thisAmount.ToString() + "\n";
		totalAmount += thisAmount;
	}
	// add footer lines
	result += "Amount owed is " + totalAmount.ToString() + "\n";
	result += "You earned " + frequentRenterPoints.ToString() + " frequent renter points";
	return result;
}6.运行测试,如果不通过则检查、修改代码,直到通过为止。