<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      小酌重構系列[4]——分解方法

      概述

      “分解方法”的思想和前面講到的“提取方法”、“提取方法對象”基本一致。
      它是將較大個體的方法不斷的拆分,讓每個“方法”做單一的事情,從而提高每個方法的可讀性和可維護性。
      分解方法可以看做是“提取方法”的遞歸版本,它是對方法反復提煉的一種重構策略。

      分解方法

      下圖表示了這個重構策略,第1次提煉和第2次提煉都采用了“提取方法”這個策略。

      image

      何時分解方法?

      “分解方法”最終可以讓方法的可讀性極大地增強,通常我們可以依據以下幾點來辨別方法是否需要分解:

      1. 每個方法應該只做一件事情(對事情的理解程度,決定了事情的粒度)
      2. 方法應該盡量短小,方法最好不要超過20行(依不同情況,酌情考慮行數)
      3. 方法的縮進層次不宜太多,最好不要超過兩級

      4. 方法需要太多的注釋才能理解

      示例

      場景說明

      假設在企業制作年度預算的場景中,用戶需要按照如下Excel模板填寫科目、部門、各月的預算數據,然后將Excel文件導入到“預算系統”。

      image

      為了表示用戶填寫的每一行預算數據,開發人員在系統中設計了兩個class:BudgetItem(預算項)和BudgetItemDetail(預算項明細)。
      上圖紅色方框標注的表示一個BudgetItem對象,每個藍色方框則對應一個BudgetItemDetail對象。

      image

      BudgetItem.cs和BudgetItemDetail.cs
      /// <summary>
      /// 預算項
      /// </summary>
      public class BudgetItem
      {
          public string Dept { get; set; }
          public string Account { get; set; }
          public IList<BudgetItemDetail> BudgetItemDetails { get; set; } 
      }
      
      /// <summary>
      /// 預算項明細
      /// </summary>
      public class BudgetItemDetail
      {
          public string Month { get; set; }
          public decimal Amount { get; set; }
      }

      重構前

      在表示這段邏輯時,我們編寫了一個BudgetItemImport類,用于讀取Excel并返回IList<BudgetItem>集合

      public class BudgetItemImport
      {
          private Regex _monthRegex = new Regex(@"\d{4}\\\d{2}");
      
          public IList<BudgetItem> GetBudgetItems(string path)
          {
              // 讀取Excel獲取DataTable
              DataTable table = ExcelUtil.RenderFromExcel(path);
      
              // 獲取表示月份的列名
              IList<string> monthColumns = new List<string>();
              for (var i = 0; i < table.Columns.Count; i++)
              {
                  var columnName = table.Columns[i].ColumnName;
                  if (_monthRegex.IsMatch(columnName))
                  {
                      monthColumns.Add(columnName);
                  }
              }
      
              // 遍歷DataRow獲取BudgetItems
              IList<BudgetItem> budgetItems = new List<BudgetItem>();
              for (var i = 1; i < table.Rows.Count; i++)
              {
                  // 獲取DataRow
                  DataRow dataRow = table.Rows[i];
      
                  // 創建BudgetItem對象,并設置部門和科目信息
                  BudgetItem budgetItem = new BudgetItem
                  {
                      Dept = dataRow[0].ToString(),
                      Account = dataRow[1].ToString()
                  };
      
                  // 創建BudgetItemDetail集合
                  IList<BudgetItemDetail> budgetItemDetails = new List<BudgetItemDetail>();
                  foreach (var column in monthColumns)
                  {
                      // 創建BudgetItemDetail對象,并設置預算月份和相應金額
                      BudgetItemDetail detail = new BudgetItemDetail
                      {
                          Month = column,
                          Amount = Convert.ToDecimal(dataRow[column])
                      };
      
                      budgetItemDetails.Add(detail);
                  }
                  budgetItem.BudgetItemDetails = budgetItemDetails;
                  budgetItems.Add(budgetItem);
              }
      
              return budgetItems;
          } 
      }
      

      以上這段代碼,如果沒有這些注釋,GetBudgetItems()方法是比較難以讀懂的。
      接下來,我們采用“分解方法”這個策略來對它重構。

      第一次重構

      我們粗略分析一下,可以得知GetBudgetItems()方法一共做了3件事情,下圖闡述了它的邏輯。

      image
      秉承著“一個方法只做一件事情”的原則,我們將這3件事情拆分出來,使其變成3個方法。

      public class BudgetItemImport
      {
          private Regex _monthRegex = new Regex(@"\d{4}\\\d{2}");
      
          public IList<BudgetItem> GetBudgetItems(string path)
          {
              // 讀取Excel獲取DataTable
              DataTable table = ExcelUtil.RenderFromExcel(path);
      
              // 獲取表示月份的列名
              IList<string> monthColumns = GetMonthColumns(table.Columns);
      
              // 讀取DataTable獲取BudgetItem集合
              return GetBudgetItemsFromDataTable(table, monthColumns);
          }
      
          // 獲取表示月份的列名
          private IList<string> GetMonthColumns(DataColumnCollection collection)
          {
              IList<string> monthColumns = new List<string>();
              for (var i = 0; i < collection.Count; i++)
              {
                  var columnName = collection[i].ColumnName;
                  if (_monthRegex.IsMatch(columnName))
                  {
                      monthColumns.Add(columnName);
                  }
              }
              return monthColumns;
          }
      
          // 讀取DataTable獲取BudgetItem集合
          private IList<BudgetItem> GetBudgetItemsFromDataTable(DataTable table, IList<string> monthColumns)
          {
              // 遍歷DataRow獲取BudgetItems
              IList<BudgetItem> budgetItems = new List<BudgetItem>();
              for (var i = 1; i < table.Rows.Count; i++)
              {
                  DataRow dataRow = table.Rows[i];
      
                  // 創建BudgetItem對象,并設置部門和科目信息
                  BudgetItem budgetItem = new BudgetItem
                  {
                      Dept = dataRow[0].ToString(),
                      Account = dataRow[1].ToString()
                  };
      
                  // 創建BudgetItemDetail集合,并設置每個BudgetItemDetail對象的月份和金額
                  IList<BudgetItemDetail> budgetItemDetails = monthColumns.Select(column => new BudgetItemDetail
                  {
                      Month = column,
                      Amount = Convert.ToDecimal(dataRow[column])
                  }).ToList();
      
                  budgetItem.BudgetItemDetails = budgetItemDetails;
      
                  budgetItems.Add(budgetItem);
              }
      
              return budgetItems;
          } 
      }
      

      第二次重構

      雖然GetBudgetItems()拆分成了3個方法,但新追加的GetBudgetItemsFromDataTable()方法還是不具備良好的可讀性,這個方法我們仍然需要借助注釋才能讀懂。
      我們再具體分析這個方法內部的邏輯,GetBudgetItemsFromDataTable()這個方法也做了3件事情,見下圖:

      image

      按照這個更加明細的邏輯流程,我們將這3件事情再拆分出來。

      public class BudgetItemImport
      {
          private Regex _monthRegex = new Regex(@"\d{4}\\\d{2}");
      
          public IList<BudgetItem> GetBudgetItems(string path)
          {
              // 讀取Excel獲取DataTable
              DataTable table = ExcelUtil.RenderFromExcel(path);
      
              // 獲取表示月份的列名
              IList<string> monthColumns = GetMonthColumns(table.Columns);
      
              // 讀取DataTable獲取BudgetItem集合
              return GetBudgetItemsFromDataTable(table, monthColumns);
          }
      
          // 獲取表示月份的列名
          private IList<string> GetMonthColumns(DataColumnCollection collection)
          {
              IList<string> monthColumns = new List<string>();
              for (var i = 0; i < collection.Count; i++)
              {
                  var columnName = collection[i].ColumnName;
                  if (_monthRegex.IsMatch(columnName))
                  {
                      monthColumns.Add(columnName);
                  }
              }
              return monthColumns;
          }
      
          // 讀取DataTable獲取BudgetItem集合
          private IList<BudgetItem> GetBudgetItemsFromDataTable(DataTable table, IList<string> monthColumns)
          {
              IList<BudgetItem> budgetItems = new List<BudgetItem>();
              foreach (DataRow dataRow in table.Rows)
              {
                  BudgetItem budgetItem = GetBudgetItemFromDataRow(dataRow, monthColumns);
                  budgetItems.Add(budgetItem);
              }
              return budgetItems;
          }
      
          // 創建BudgetItem對象,并設置部門和科目信息
          private BudgetItem GetBudgetItemFromDataRow(DataRow dataRow, IList<string> monthColumns)
          {
              BudgetItem budgetItem = new BudgetItem
              {
                  Dept = dataRow[0].ToString(),
                  Account = dataRow[1].ToString(),
                  BudgetItemDetails = GetBudgetItemDetailsFromDataRow(dataRow, monthColumns)
              };
              return budgetItem;
          }
      
          // 創建BudgetItemDetail集合,并設置每個BudgetItemDetail對象的月份和金額
          private IList<BudgetItemDetail> GetBudgetItemDetailsFromDataRow(DataRow dataRow, 
                                                                          IList<string> monthColumns)
          {
              return monthColumns.Select(column => new BudgetItemDetail
              {
                  Month = column,
                  Amount = Convert.ToDecimal(dataRow[column]),
              }).ToList();
          }
      }
      

      經過這次重構后,BudgetItemImport類的可讀性已經很好了。每個方法都只做一件事情,每個方法都很短小,都不超過20行,我們甚至不需要為這些方法寫注釋了。

      小結

      在經歷過兩次重構后,我們得到了結構良好的代碼。回顧這個示例的重構過程,我們可以用下面一副圖來表示。

      image

      寫代碼和寫別的東西很像。在寫文章時,你先想什么就寫什么,然后再打磨它。初稿也許丑陋無序,你就雕章琢句,直至達到你心目中的樣子。
      我們并不能直接寫出結構和可讀性良好的方法,一開始我們的方法寫得復雜且冗長,包含了各種循環、判斷、縮進和注釋。
      然后我們打磨這些代碼,通過分解方法逐一解決這些問題。

      posted @ 2016-05-02 23:38  keepfool  閱讀(1454)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 久久人妻精品大屁股一区| 日本福利一区二区精品| 激,情四虎欧美视频图片| 国产成人精品中文字幕| 亚洲日本va午夜中文字幕久久| 天堂网av最新版在线看| 国产精品无码成人午夜电影| 国产a在视频线精品视频下载| 日韩av一区二区高清不卡| 国产人成777在线视频直播| 日韩中文字幕精品人妻| 免费国产拍久久受拍久久| 中文字幕一区二区三区久久蜜桃| 色偷偷亚洲女人天堂观看| 99久久精品国产一区二区| 亚洲精品成人片在线观看精品字幕| 亚洲高潮喷水无码AV电影| 爱性久久久久久久久| 91久久久久无码精品露脸| 日韩中文字幕亚洲精品| 精品国产这么小也不放过| 人妻丝袜无码专区视频网站| 日韩国产精品无码一区二区三区| 亚洲国产成人无码av在线播放 | 亚洲熟妇在线视频观看| 国产超高清麻豆精品传媒麻豆精品 | 国产av中文字幕精品| 自拍视频在线观看成人| 一个人看的www免费高清视频| 西城区| 亚洲精品有码在线观看| 亚洲色欲色欱WWW在线| 亚洲伊人成无码综合网| 国产偷国产偷亚洲高清午夜| 少妇高潮喷水正在播放| 人妻人人做人碰人人添| 国产午夜福利不卡在线观看| 久久国产综合色免费观看| 99re热这里只有精品视频| 亚洲精品无码在线观看| 婷婷四房播播|