日期:2014-05-18 浏览次数:21494 次
上一篇主要重构了Statement方法,在大刀阔斧的调整后,总算是得到了一个易于理解的方法体。当然,其中会带来潜在的效率问题,但记住一点,起码所有的事情都是经过权衡和决策的。可以“果断”来形容,而那种不明就里地乱来属于“武断”又或者说是“鲁莽”的行为当然不被推荐,它们的区别也就在于是否有全面的权衡与决策。
首先,列出到现在为止,Movie类和Rental类的代码如下:
public class Movie
{
	public const int CHILDRENS = 2;
	public const int REGULAR = 0;
	public const int NEW_RELEASE = 1;
	public string Title { get; private set; }
	public int PriceCode { get; private set; }
	
	public Movie(string title, int priceCode)
	{
		Title = title;
		PriceCode = priceCode;
	}
}
public class Rental
{
	public Movie Movie { get; private set; }
	public int DaysRented { get; private set; }
	public double Charge
	{
		get
		{
			double result = 0;
			switch (Movie.PriceCode)
			{
				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;
		}
	}
	public int FrequentRenterPoints
	{
		get
		{
			if (Movie.PriceCode == Movie.NEW_RELEASE && DaysRented > 1)
			{
				return 2;
			}
			else
			{
				return 1;
			}
		}
	}
	public Rental(Movie rented, int days)
	{
		Movie = rented;
		DaysRented = days;
	}
}public double ChargeFor(int daysRented)
{
	double result = 0;
	switch (PriceCode)
	{
		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;
}注意,在代码迁移时,可能存在一些问题,诸如原本PriceCode是使用Rental的Movie对象来调用的,而现在因为它成为了自身的属性,所以也就没有必要使用Movie对象了。public double Charge
{
	get
	{
		return Movie.ChargeFor(DaysRented);
	}
}
3.运行单元测试,如果不通过则调试、修改直到通过为止
二、用多态来封装价格算法
其实,就《重构》中所列出的这份代码而言,个人认为不需要更多的优化了。在整个程序中只有一个地方需要对PriceCode进行分派处理,这样的集中也是一种不错的选择——毕竟需要调整价格计算算法时,我们一定会直接定位到该ChargeFor方法。而什么样的信号会明确地告诉我们需要把switch转换成多态呢?我想应该是在代码中出现两处以上对PriceCode的switch分派处理时,这时,多态化的信号就很明确了。而《重构》更多的是想以此为例,演示如何用多态的技术来解决类似的问题。
为了要引入多态,就开始需要介入设计模式了。有很多人可能不了解它,甚至会因此产生抗拒的心态。其实完全没必要,设计模式说白了都很简单,尤其是它们的实现。最难的只是要活学活用它们的适用情境。
1.创建一个Price接口,用来表示影片的可计算概念
public interface Price
{
	double ChargeFor(int daysRented);
}2.创建一个实现了Price接口的Regular类,实现对REGULAR类型影片的价格计算。重新审视关于该类型影片价格的计算方法,可以得到下面代码:public sealed class RegularPrice : Price
{
	public double ChargeFor(int daysRented)
	{
		if (daysRented > 2)
		{
			return 2 + (daysRented - 2) * 1.5;
		}
		else
		{
			return 2;
		}
	}
}3.修改Movie.ChargeFor中,关于REGULAR影片价格计算的片段,如下public double ChargeFor(int daysRented)
{
	double result = 0;
	switch (PriceCode)
	{
		case Movie.REGULAR:
			result = (new RegularPrice()).ChargeFor(daysRented);
			break;
		case Movie.NEW_RELEASE:
			result += daysRented * 3;
			break;
		case Movie.CHILDRENS:
			result += 1.5;
			if (daysRented > 3)
				result += (daysR