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

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

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

      小酌重構(gòu)系列[2]——提取方法、提取方法對(duì)象

      前言

      “藝術(shù)源于生活”——代碼也源于生活,你在生活中的一些行為習(xí)慣,可能會(huì)恰如其分地體現(xiàn)在代碼中。
      當(dāng)實(shí)現(xiàn)較為復(fù)雜的功能時(shí),由于它包含一系列的邏輯,我們傾向于編寫一個(gè)“大方法”來(lái)實(shí)現(xiàn)。
      為了使項(xiàng)目便于維護(hù),以及增強(qiáng)代碼的可讀性,我們有必要對(duì)“大方法”的邏輯進(jìn)行整理,并提取出分散的“小方法”。
      這就是本文要講的兩種重構(gòu)策略:提取方法、提取方法對(duì)象。

      如何快速地找到想讀的書?

      在生活中,我是一個(gè)比較隨意的人,平時(shí)也買了不少書去看。
      我的書柜不夠大,且已經(jīng)裝滿了書,每當(dāng)讀完一本書時(shí),我懶得花些時(shí)間整理,想著以后再去整理這些書籍,所以我通常都將這些書塞到一個(gè)大箱子里面。
      每次要重讀某些書時(shí),我恨不得把這個(gè)箱子翻個(gè)底朝天,在花費(fèi)“九牛二虎之力”之后,我終于找到了要看的書。
      然后,我把其他翻出來(lái)的書再塞回去。

      每次找書,我總是經(jīng)歷千辛萬(wàn)苦,弄得家里的地板一片狼藉,還得被媳婦兒臭罵一頓。
      1ADC1548

      箱子那么大,所有的書都放在一個(gè)箱子里,一整箱書都沒(méi)有分類,有些書藏得很深,找起書來(lái)的確不方便。

      后來(lái),我想到了一個(gè)方法——最近快遞小哥送貨的包裝紙箱還在家里,這些箱子不會(huì)很大,但裝書應(yīng)該綽綽有余,何不把這些箱子利用起來(lái)?
      于是,我就動(dòng)手挑選了一些大小合適的小紙箱,用簽字筆給每個(gè)紙箱做了一個(gè)標(biāo)記。

      1號(hào)紙箱,裝ASP.NET編程相關(guān)的書
      2號(hào)紙箱,裝架構(gòu)設(shè)計(jì)相關(guān)的書
      3號(hào)紙箱,裝管理相關(guān)的書

      N號(hào)紙箱,裝旅游相關(guān)的書

      自從將書分類裝到各個(gè)小紙箱后,通過(guò)標(biāo)記我總能很快地找到想讀的書了,媳婦兒再也不為這事兒罵我了。
       1ADCD1B2

      在生活中,很多讀者可能也遇到過(guò)此類問(wèn)題,為什么找個(gè)東西就這么難呢?

      生活中的習(xí)慣會(huì)折射到編程中。當(dāng)寫完一個(gè)方法時(shí),有時(shí)因懶惰心理和拖延習(xí)慣,我們可能會(huì)對(duì)自己說(shuō):“這個(gè)方法有時(shí)間再整理吧,先完成后續(xù)的功能”。
      結(jié)果就是抱著這種心理,這個(gè)方法一直到項(xiàng)目上線都沒(méi)有整理過(guò)。
      在項(xiàng)目維護(hù)期間,需要修改這個(gè)方法時(shí),再次閱讀到這個(gè)方法,我們不禁抱怨:“我擦,這方法怎么這么長(zhǎng),這是誰(shuí)寫的,我給他666!哎呦,不對(duì),這好像是我自己寫的!”
       1AD76044 

      提取方法

      當(dāng)一個(gè)方法包含實(shí)現(xiàn)一個(gè)功能的所有邏輯時(shí),不僅方法會(huì)看起來(lái)比較臃腫(可讀性差),也會(huì)給將來(lái)的維護(hù)造成困擾,每次改動(dòng)都會(huì)讓你如履薄冰,并且較大可能帶來(lái)新的bug。這不符合我們“將來(lái)的利益”,我們可以使用提取方法的重構(gòu)策略來(lái)規(guī)避這個(gè)問(wèn)題。

      下面是我對(duì)提取方法的定義:

      如果一個(gè)方法包含多個(gè)邏輯,我們應(yīng)將每個(gè)邏輯提取出來(lái),并確保每個(gè)方法只做一件事情。

      下圖表示了這個(gè)重構(gòu)策略(藍(lán)色為重構(gòu)前,紅色為重構(gòu)后)。
      image

      示例

      重構(gòu)前

      下面這段代碼定義了一個(gè)Receipt類,用于描述收入信息,并計(jì)算總收入。

      using System.Collections.Generic;
      
      namespace ExtractMethod.Before
      {
          public class Receipt
          {
              public IList<decimal> Discounts { get; set; }
              public IList<decimal> ItemTotals { get; set; }
      
              public decimal CalculateGrandTotal()
              {
                  decimal subTotal = 0m;
      
                  // 計(jì)算subTotal
                  foreach (decimal itemTotal in ItemTotals)
                      subTotal += itemTotal;
      
                  // 計(jì)算折扣
                  if (Discounts.Count > 0)
                  {
                      foreach (decimal discount in Discounts)
                      {
                          subTotal -= discount;
                      }
                  }
      
                  // 計(jì)算稅額
                  decimal tax = subTotal*0.065m;
      
                  subTotal += tax;
      
                  return subTotal;
              }
          }
      }

      CalculateGrandTotal()方法包含了多處邏輯:計(jì)算subTotal,計(jì)算折扣,計(jì)算稅額。
      這幾處邏輯是相對(duì)獨(dú)立的,我們可以將其提取出來(lái),重構(gòu)為3個(gè)方法。

      重構(gòu)后

      重構(gòu)后,CalculateGrandTotal()方法只包含調(diào)用各個(gè)子方法的邏輯,這已經(jīng)精簡(jiǎn)了很多,可讀性也有所增強(qiáng)。

      image

      using System.Collections.Generic;
      using System.Linq;
      
      namespace ExtractMethod.After
      {
          public class Receipt
          {
              public IList<decimal> Discounts { get; set; }
              public IList<decimal> ItemTotals { get; set; }
      
              public decimal CalculateGrandTotal()
              {
                  // 計(jì)算subTotal
                  decimal subTotal = CalculateSubTotal();
                  // 計(jì)算折扣
                  subTotal = CalculateDiscounts(subTotal);
                  // 計(jì)算稅額
                  subTotal = CalculateTax(subTotal);
      
                  return subTotal;
              }
      
              // 計(jì)算subTotal
              private decimal CalculateSubTotal()
              {
                  return ItemTotals.Sum();
              }
      
              // 計(jì)算折扣
              private decimal CalculateDiscounts(decimal subTotal)
              {
                  if (Discounts.Count > 0)
                  {
                      subTotal = Discounts.Aggregate(subTotal, (current, discount) => current - discount);
                  }
                  return subTotal;
              }
      
              // 計(jì)算稅額
              private decimal CalculateTax(decimal subTotal)
              {
                  decimal tax = subTotal * 0.065m;
                  subTotal += tax;
                  return subTotal;
              }
          }
      }
      

      二次重構(gòu)

      我認(rèn)為這仍然不夠。CalculateGrandTotal() 方法所表現(xiàn)的“語(yǔ)義”,是為了計(jì)算收入總額。
      但上面這段代碼不能讓我們快速地知道這個(gè)語(yǔ)義,我們需要通過(guò)3個(gè)子方法來(lái)理解這個(gè)語(yǔ)義。

      “計(jì)算收入總額”本質(zhì)上是有一個(gè)公式的,即“收入總額 = (各項(xiàng)子收入總和 - 折扣總和) * (1 + 稅率)”,公式的右側(cè)是一個(gè)簡(jiǎn)單的三項(xiàng)式。
      這個(gè)方法沒(méi)有體現(xiàn)”公式“這個(gè)概念,為了讓這段代碼OO的味道更濃厚一些。
      我們?cè)俅螌?duì)其重構(gòu),將公式右側(cè)的每一項(xiàng)提取為屬性,每一項(xiàng)的計(jì)算邏輯都通過(guò)get屬性體現(xiàn)。

      image

      using System.Collections.Generic;
      using System.Linq;
      
      namespace ExtractMethod.After
      {
          public class Receipt2
          {
              private IList<decimal> Discounts { get; set; }
              private IList<decimal> ItemTotals { get; set; }
      
              public decimal CalculateGrandTotal()
              {
                  // 收入總額 = (各項(xiàng)子收入總和 - 折扣總和) * (1 + 稅率)
                  decimal grandTotal = (SubTotal - TotalDiscounts) * (1 + TaxRate);
                  return grandTotal;
              }
      
              // 獲取subTotal
              private decimal SubTotal
              {
                  get { return ItemTotals.Sum(); }
              }
      
              // 獲取TotalDiscounts
              private decimal TotalDiscounts
              {
                  get { return Discounts.Sum(); }
              }
      
              // 獲取TaxRate
              private decimal TaxRate
              {
                  get { return 0.065m; }
              }
          }
      }

      再次重構(gòu)后的代碼,是不是一目了然?
      這里可能有人會(huì)疑惑了,本文不是講提取方法的嗎?現(xiàn)在怎么去提取屬性了呢?
      在C#中,屬性的本質(zhì)是字段的get, set方法,所以它仍然算是提取方法。

      請(qǐng)注意,并不是所有情況下,都適合使用提取屬性來(lái)代替提取方法。我的建議是,當(dāng)提取的方法邏輯較少時(shí),可以使用提取屬性代替。當(dāng)提取的方法邏輯較多時(shí),如果使用提取屬性代替,也會(huì)讓人覺(jué)得困擾。因?yàn)閷傩允菫榱嗣枋鰧?duì)象的特征,描述特征的過(guò)程如果較為復(fù)雜,會(huì)讓人難以理解,我們應(yīng)該keep it simple!

      提取方法對(duì)象

      以上示例描述了一個(gè)客觀對(duì)象:“收入”,這個(gè)對(duì)象包含兩個(gè)層面的“語(yǔ)義”——“收入相關(guān)的信息”和“計(jì)算收入的方法”。
      “收入相關(guān)的信息”用名詞來(lái)體現(xiàn),它揭示了收入客觀存在的特征(例如:所有的子收入、折扣和稅率)。
      “計(jì)算收入的方法”用動(dòng)詞來(lái)體現(xiàn),它揭示了收入的計(jì)算過(guò)程。

      這兩層“語(yǔ)義”可以看做兩種不同的職責(zé),為了將這兩層“語(yǔ)義”隔離開(kāi)來(lái),我們可以將“計(jì)算收入的方法”提取為一個(gè)新的對(duì)象。

      using System.Collections.Generic;
      using System.Linq;
      
      namespace ExtractMethod.After
      {
          /// <summary>
          /// 描述收入相關(guān)的信息
          /// </summary>
          public class Receipt
          {
              public IList<decimal> Discounts { get; set; }
              public IList<decimal> ItemTotals { get; set; }
      
              // 獲取TaxRate
              public decimal TaxRate
              {
                  get { return 0.065m; }
              }
      
              public decimal CalculateGrandTotal()
              {
                  return new ReceiptCalculator(this).CalculateGrandTotal();
              }
          }
      
          /// <summary>
          /// 描述收入的計(jì)算方法
          /// </summary>
          public class ReceiptCalculator
          {
              private readonly Receipt _receipt;
      
              public ReceiptCalculator(Receipt receipt)
              {
                  _receipt = receipt;
              }
      
              public decimal CalculateGrandTotal()
              {
                  decimal grandTotal = (SubTotal - TotalDiscounts) * (1 + _receipt.TaxRate);
                  return grandTotal;
              }
      
              // 獲取subTotal
              private decimal SubTotal
              {
                  get { return _receipt.ItemTotals.Sum(); }
              }
      
              // 獲取TotalDiscounts
              private decimal TotalDiscounts
              {
                  get { return _receipt.Discounts.Sum(); }
              }
          }
      }
      

      這則代碼將Receipt對(duì)象的“計(jì)算收入的方法”提取到了ReceiptCalculator對(duì)象,Receipt對(duì)象則只保留了屬性和精簡(jiǎn)的CalculateGrandTotal()方法。

      “提取方法對(duì)象”也是一個(gè)不錯(cuò)的重構(gòu)策略,“提取方法對(duì)象”有什么作用呢?它可以精確類的職責(zé),控制類的粒度。
      一開(kāi)始,我們用Receipt來(lái)描述“收入”這件事情;后來(lái)我們發(fā)現(xiàn)這件事情可以拆分為兩個(gè)細(xì)節(jié),“收入相關(guān)的信息”和“計(jì)算收的方法”,于是我們將這兩個(gè)細(xì)節(jié)拆分開(kāi)來(lái)。

      到這里,也許大家又能看出一點(diǎn)點(diǎn)”O(jiān)O”的味道了,它體現(xiàn)了我們看待客觀事物的角度,以及對(duì)客觀事物的理解程度。OO的過(guò)程是我們對(duì)客觀事物的探索和認(rèn)知過(guò)程,它也會(huì)隨著我們了解到更多的事物細(xì)節(jié)而進(jìn)化。

      posted @ 2016-04-26 00:33  keepfool  閱讀(4078)  評(píng)論(18)    收藏  舉報(bào)
      主站蜘蛛池模板: 又大又紧又粉嫩18p少妇| 日韩不卡1卡2卡三卡网站| 欧美人与性囗牲恔配| 青青草原网站在线观看| 日本中文一二区有码在线| 成av人电影在线观看| 亚洲欧美日韩综合一区在线| 疯狂的欧美乱大交| 国产一区二区三中文字幕| 无套内内射视频网站| 国产第一页浮力影院入口| 日本一区二区三区专线| 香蕉影院在线观看| 性色av不卡一区二区三区| 久久综合97丁香色香蕉| 国产成人亚洲精品狼色在线 | 精品午夜福利短视频一区| 亚洲AV无码破坏版在线观看| 精品国产成人网站一区在线| 怀化市| 熟女亚洲综合精品伊人久久 | 最新亚洲av日韩av二区| 18禁无遮挡啪啪无码网站破解版| 欧美激情一区二区| 国内精品人妻一区二区三区| 澳门永久av免费网站| 平舆县| 亚洲护士一区二区三区| 97久久超碰亚洲视觉盛宴| 中文字幕国产精品二区| 国产在线无码精品无码| 国产精品人伦一区二区三| 亚洲国内精品一区二区| 亚洲熟女综合色一区二区三区| 亚洲欧美偷国产日韩| av午夜福利亚洲精品福利| 国产乱子伦一区二区三区视频播放| 西昌市| 国产午夜福利视频第三区| 国产精品国语对白露脸在线播放 | 国产视频一区二区三区麻豆|