七、重構4:使用以查詢取代臨時變數再次對Statement()方法進行重構

1. 經過了之前幾篇文章的重構後,Customer中的statement()方法的具體程式碼,如下圖所示。在計算每部電影的金額和積分時,我們呼叫的是Rental類的物件的相應的方法。下圖中的方法與充電項計費專案的原始程式碼中的方法相比可謂是簡潔了許多,而且易於理解與維護。

2.不過上面的程式碼仍然有重構的空間,舉個例子,如果我們要將結果以HTML的形式進行組織的話,我們需要將上面的程式碼進行復制,然後修改result變數的文字組織方式即可。這可能就是程式設計師經常做的事情Ctrl+C、Ctrl+V,很多程式設計師是這樣來修改程式碼的,這種修改程式碼快速,功能實現方便,但是這樣的修改程式碼會給我們的系統遺留很多無用的程式碼。使用Ctrl+C、Ctrl+V這種非常方便的方式來修改程式碼,會造成方法中的好多臨時變數都被複制一份,這是完全相同的,這樣就容易產生重複的程式碼。在這種情況下,我們需要使用“Replace Temp with Query”(已查詢取代臨時變數)的重構手法來取出上圖所示的紅框中的臨時變數。

上圖中紅框所框出來的每個臨時變數我們都會提取出一個查詢方法,下圖中所示的程式碼,就是使用“Replace Temp with Query”(已查詢取代臨時變數)規則重構後的Statement()方法,以及提取的兩個查詢函式。

3.經過上面這些步驟的重構,Customer類的具體程式碼如下所示:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace LeasePowerBank
  8. {
  9.  
  10. /// <summary>
  11. /// 客戶類
  12. /// </summary>
  13. public class Customer
  14. {
  15.  
  16. string Name;//使用者名稱稱
  17. public List<Rental> listRentals=new List<Rental>();//使用者租賃的充電寶
  18. public Customer(string name)
  19. {
  20.  
  21. Name = name;
  22. }
  23.  
  24. public void AddRental(Rental rental)
  25. {
  26.  
  27. listRentals.Add(rental);
  28. }
  29.  
  30. public string Statement()
  31. {
  32.  
  33. string result = $"{Name} 的租賃賬單:\n";
  34.  
  35. result += $"總金額為:{GetTotalAmount()}\n";
  36. result += $"你本次獲得了:{GetTotalFrequentRenterPoints()}積分 ";
  37. return result;
  38.  
  39. }
  40.  
  41. /// <summary>
  42. /// 計算總金額
  43. /// </summary>
  44. private decimal GetTotalAmount()
  45. {
  46.  
  47. decimal totalAmount = 0M; //總金額
  48. foreach (var item in listRentals)
  49. {
  50.  
  51. totalAmount+= item.GetAmount();//總價計算
  52.  
  53. }
  54.  
  55. return totalAmount;
  56.  
  57. }
  58.  
  59. /// <summary>
  60. /// 計算積分
  61. /// </summary>
  62. private decimal GetTotalFrequentRenterPoints()
  63. {
  64. int frequentRenterPoints = 0; //使用者積分
  65.  
  66. foreach (var item in listRentals)
  67. {
  68. frequentRenterPoints += item.GetFrequentRenterPoints();//計算積分
  69. }
  70.  
  71. return frequentRenterPoints;
  72. }
  73. }
  74. }
 
4. 我們的測試用例依然不變。在每次重構後我們都需要呼叫上述的測試用例來檢查重構是否產生了副作用。現在我們的類間的依賴關係沒怎麼發生變化,只是相應類中的方法有些變化。在Visual Studio 2019的選單欄上找到“測試-->執行所有測試”選單項。或者在“測試資源管理器中”選擇 “在檢視中執行所有測試”按鈕, 執行測試用例。監測重構的結果是否正確。如下圖。