日期:2014-05-18 浏览次数:21486 次
上一篇主要重构了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