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

我们继续重构,接下来我们遇到的问题是switch语句,书上说最好不要在另一个对象的属性基础上运用switch语句。如果不得不使用,也应该在对象自己的数据上使用而不是在别人的对象上使用。

我们看到Rental的getCharge()里边的switch语句中的选择条件是getMovie().getPriceCode(),所以我们需要将getCharge()放到Movie类中。

下边是新增加的Movie中的getCharge()和修改过的Rental中的getCharge():

// method in Movie
public double getCharge(int daysRented)
{
double result = 0;
// determine amounts for each line
switch(getPriceCode())
{
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;
}
// Method in Rental
public double getCharge()
{
return _movie.getCharge(_daysRented);
}

之后,我们继续重构,我们以相同的方法处理常客积分的计算,这样我们就把根据影片类型而变化的所有东西都放到了Movie类中。

// Movie中增加的函数
public int getFrequentRenterPoints(int daysRented)
{
if((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)
{
return 2;
}
else
{
return 1;
}
}
// Rental中修改的函数
public int getFrequentRentalPoints()
{
return _movie.getFrequentRenterPoints(_daysRented);
}

继续重构,我们来到了继承。

我们有数种影片类型,它们以不同的方式回答相同的问题。这听起来很像子类的工作。我们可以建立Movie的三个子类,每个子类都有自己的计算方法。

下边是UML图

继续重构:

首先我们使用Replace Type Code WithState/Strategy,第一步骤是针对类型代码使用Self Encapsulate Field,确保任何时候都通过取值函数和设置函数来访问类型代码。

我们直接修改Movie的构造函数:

    public Movie(String title, int priceCode)
{
_title = title;
_priceCode = priceCode;
}

修改为:

    public Movie(String title, int priceCode)
{
_title = title;
setPriceCode(priceCode);
}

接下来,我们需要新建4个类:

public abstract class Price 
{
abstract int getPriceCode();
}
public class RegularPrice extends Price 
{

@Override
int getPriceCode()
{
return Movie.REGULAR;
}

}
public class NewReleasePrice extends Price 
{

@Override
int getPriceCode()
{
return Movie.NEW_RELEASE;
}

}
public class ChildrensPrice extends Price 
{

@Override
int getPriceCode()
{
return Movie.CHILDRENS;
}

}

然后我们就可以使用新建的这些类了,我们需要修改Movie类中的“价格代号”访问函数,让他们使用新建的类。

下边是修改前的样子:

    private int _priceCode;

public int getPriceCode()
{
return _priceCode;
}

public void setPriceCode(int priceCode)
{
_priceCode = priceCode;
}

这意味着我们必须在Movie类中保存一个Price对象,而不再是保存一个_priceCode变量了,此外我们还需要修改访问函数:

    private Price _price;

public int getPriceCode()
{
return _price.getPriceCode();
}

public void setPriceCode(int movieType)
{
switch(movieType)
{
case REGULAR:
_price = new RegularPrice();
break;
case CHILDRENS:
_price = new ChildrensPrice();
break;
case NEW_RELEASE:
_price = new NewReleasePrice();
break;
}
}

接下来我们要对getCharge()进行Move Method,从Movie转移到Price中

转移前的代码:

// Method in Movie
public double getCharge(int daysRented)
{
double result = 0;
// determine amounts for each line
switch(getPriceCode())
{
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;
}

新的Price,ChildrenPrice,RegularPrice和NewReleasePrice类:

public abstract class Price 
{
abstract int getPriceCode();
abstract double getCharge(int daysRented);
}
public class ChildrensPrice extends Price 
{

@Override
int getPriceCode()
{
return Movie.CHILDRENS;
}

@Override
double getCharge(int daysRented)
{
double result = 1.5;
if(daysRented > 3)
{
result += (daysRented - 3) * 1.5;
}
return result;
}

}
public class NewReleasePrice extends Price 
{

@Override
int getPriceCode()
{
return Movie.NEW_RELEASE;
}

@Override
double getCharge(int daysRented)
{
return daysRented * 3;
}

}
public class RegularPrice extends Price 
{

@Override
int getPriceCode()
{
return Movie.REGULAR;
}

@Override
double getCharge(int daysRented)
{
double result = 2;
if(daysRented > 2)
{
result += (daysRented - 2) * 1.5;
}
return result;
}

}

OK,所有的准备工作都做完了,我们来修改一下Movie的getCharge()函数:

修改前:

    public double getCharge(int daysRented)
{
double result = 0;
// determine amounts for each line
switch(getPriceCode())
{
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 double getCharge(int daysRented)
{
return _price.getCharge(daysRented);
}

OK,我们继续用同样的方法处理getFrequentRenterPoints()

首先我们在Price类中添加函数:

public abstract class Price 
{
abstract int getPriceCode();
abstract double getCharge(int daysRented);
int getFrequentRenterPoints(int daysRented)
{
return 1;
}
}

接着我们需要重写NewReleasePrice中的函数:

    @Override
int getFrequentRenterPoints(int daysRented)
{
if(daysRented > 1)
{
return 2;
}
else
{
return 1;
}
}

OK,做好准备我们就可以修改Movie中的getFrequentRenterPoints了

    public int getFrequentRenterPoints(int daysRented)
{
return _price.getFrequentRenterPoints(daysRented);
}

OK,我们的重构到此结束了。
















原文地址:https://www.cnblogs.com/xiaobo68688/p/2316460.html