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