1.封装集合
在某些场景中,向类的使用者隐藏类中的完整集合是一个很好的做法,比如对集合的 add/remove 操作中包 含其他的相关逻辑时。因此,以可迭代但不直接在集合上进行操作的方式来暴露集合,是个不错的主意。
public class Order
{
private int _orderTotal;
private List<OrderLine> _orderLines;
public IEnumerable<OrderLine> OrderLines
{
get { return _orderLines; }
}
public void AddOrderLine(OrderLine orderLine)
{
_orderTotal += orderLine.Total;
_orderLines.Add(orderLine);
}
public void RemoveOrderLine(OrderLine orderLine)
{
orderLine = _orderLines.Find(o => o == orderLine);
if (orderLine == null) return;
_orderTotal -= orderLine.Total;
_orderLines.Remove(orderLine);
}
}
我们对集合进行了封装,没有将 Add/Remove 方法暴露给类的使用者。在.NET Framework 中,有 些类如 ReadOnlyCollection,会由于封装集合而产生不同的行为,但它们各自都有防止误解的说明。这是一 个非常简单但却极具价值的重构,可以确保用户不会误用你暴露的集合,避免代码中的一些 bug。
2.Move方法
重构同样非常简单,以至于人们并不认为这是一个有价值的重构。迁移方法(Move Method),顾名 思义就是将方法迁移到合适的位置。在开始重构前,我们先看看一下代码:
public class BankAccount
{
public BankAccount(int accountAge, int creditScore, AccountInterest accountInterest)
{
AccountAge = accountAge;
CreditScore = creditScore;
AccountInterest = accountInterest;
}
public int AccountAge { get; private set; }
public int CreditScore { get; private set; }
public AccountInterest AccountInterest { get; private set; }
public double CalculateInterestRate()
{
if (CreditScore > 800)
return 0.02;
if (AccountAge > 10)
return 0.03;
return 0.05;
}
}
public class AccountInterest
{
public BankAccount Account { get; private set; }
public AccountInterest(BankAccount account)
{
Account = account;
}
public double InterestRate
{
get { return Account.CalculateInterestRate(); }
}
public bool IntroductoryRate
{
get { return Account.CalculateInterestRate() < 0.05; }
}
}
这里值得注意的是 BankAccount.CalculateInterest 方法。当一个方法被其他类使用比在它所在类中的使用还要 频繁时,我们就需要使用迁移方法重构了——将方法迁移到更频繁地使用它的类中。由于依赖关系,该重 构并不能应用于所有实例,但人们还是经常低估它的价值。
最终的代码应该是这样的:
public class BankAccount
{
public BankAccount(int accountAge, int creditScore, AccountInterest accountInterest)
{
AccountAge = accountAge;
CreditScore = creditScore;
AccountInterest = accountInterest;
}
public int AccountAge { get; private set; }
public int CreditScore { get; private set; }
public AccountInterest AccountInterest { get; private set; }
}
public class AccountInterest
{
public BankAccount Account { get; private set; }
public AccountInterest(BankAccount account)
{
Account = account;
}
public double InterestRate
{
get { return CalculateInterestRate(); }
}
public bool IntroductoryRate
{
get { return CalculateInterestRate() < 0.05; }
}
public double CalculateInterestRate()
{
if (Account.CreditScore > 800)
return 0.02;
if (Account.AccountAge > 10)
return 0.03;
return 0.05;
}
}
3.上拉法
上移方法(Pull Up Method)重构是将方法向继承链上层迁移的过程。用于一个方法被多个实现者使用时。
public abstract class Vehicle
{
// other methods
}
public class Car : Vehicle
{
public void Turn(Direction direction)
{
// code here
}
}
public class Motorcycle : Vehicle
{
}
public enum Direction
{
Left,
Right
}
如你所见,目前只有 Car 类中包含 Turn 方法,但我们也希望在 Motorcycle 类中使用。因此,如果没有基类, 我们就创建一个基类并将该方法“上移”到基类中,这样两个类就都可以使用 Turn 方法了。这样做唯一的 缺点是扩充了基类的接口、增加了其复杂性,因此需谨慎使用。只有当一个以上的子类需要使用该方法时 才需要进行迁移。如果滥用继承,系统将会很快崩溃。这时你应该使用组合代替继承。重构之后的代码如 下:
public abstract class Vehicle
{
public void Turn(Direction direction)
{
// code here
}
}
public class Car : Vehicle
{
}
public class Motorcycle : Vehicle
{
}
public enum Direction
{
Left,
Right
}
4.下推法
昨天我们介绍了将方法迁移到基类以供多个子类使用的上移方法重构,今天我们来看看相反的操作。重构 前的代码如下:
public abstract class Animal
{
public void Bark()
{
// code to bark
}
}
public class Dog : A