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