日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

31天重构学习笔记下载

發布時間:2023/12/31 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 31天重构学习笔记下载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

前兩天寫了一篇程序猿也愛學英語(上),有圖有真相的文章,寫作那篇文章只是自己一時興起,或者說是自己的興趣使然。文中的觀點只是自己的學習心得和體會,屬一家之言且鑒于本人不是學英語出身,所以也肯定有不正確的地方,也歡迎大家積極討論并給我留言,再次感謝大家的熱烈支持。關于大家詢問下篇的發布問題,我想我會盡力在周末完成。

這幾天由于剛發布完項目,所以有比較充裕的時間整理自己的知識庫,發現三年多以前學習并記錄了31天重構系列筆記,至今仍回味無窮,索性重新閱讀、糾正錯誤并重新排版整理出來,希望再次和大家一起分享。

對31天重構系列文章最早接觸是在2009年10月份,由于當時沒有訂閱Sean Chambers的 blog,所以是在國外的社區上閑逛的時候鏈接過去的。基于文章中的重構點都比較常用,所以一口氣看完了整個系列,同時由于這些重構Tips基本上項目都在使用,只是我們沒有專門把它標示和整理出來,所以當時也沒有引起多大的重視。

但就在三年前,當時我們在做一個WPF的重構項目且鑒于團隊成員技術和經驗參差不齊,非常必要專門整理一個重構的綱要,所以就收集和整理了很多的資料(31天重構也在其中)。當然這個系列除了用語重構Tips之外,也非常適合做新系統的代碼規范參考。總而言之:只要有代碼的地方,這個重構規范就很有價值。同時鑒于當時自己剛到新加坡這個美麗的城市,沒有親戚或者朋友,周末也不想出去閑逛,所以才靜下心來用了足足兩天時間學習并寫完了這個系列筆記。

31天重構這個系列和《代碼大全》、《重構:改善既有代碼的設計》比較起來最大的特點就是比較簡單且淺顯易懂。我這系列文章也都是學習并概括Sean Chambers的31天重構的知識要領,所以如果大家對這個筆記有任何的問題或者異議也可以指出,或者大家可以直接去看原文(即可掌握了技術,又可以學習英語!):

http://www.lostechies.com/blogs/sean_chambers/archive/2009/07/31/31-days-of-refactoring.aspx。


代碼下載地址:http://github.com/schambers/days-of-refactoring


目錄

  • 前言

  • 目錄

  • 31天重構學習筆記1. 封裝集合

  • 31天重構學習筆記2. 移動方法

  • 31天重構學習筆記3. 提升方法

  • 31天重構學習筆記4. 降低方法

  • 31天重構學習筆記5. 提升字段

  • 31天重構學習筆記6. 降低字段

  • 31天重構學習筆記7. 重命名(方法,類,參數)

  • 31天重構學習筆記8. 使用委派代替繼承

  • 31天重構學習筆記9. 提取接口

  • 31天重構學習筆記10. 提取方法

  • 31天重構學習筆記11. 使用策略類

  • 31天重構學習筆記12. 分解依賴

  • 31天重構學習筆記13. 提取方法對象

  • 31天重構學習筆記14. 分離職責

  • 31天重構學習筆記15. 移除重復內容

  • 31天重構學習筆記16. 封裝條件

  • 31天重構學習筆記17. 提取父類

  • 31 天重構學習筆記18. 使用條件判斷代替異常

  • 31天重構學習筆記19. 提取工廠類

  • 31天重構學習筆記20. 提取子類

  • 31天重構學習筆記21. 合并繼承

  • 31天重構學習筆記22. 分解方法

  • 31天重構學習筆記23. 引入參數對象

  • 31天重構學習筆記24. 分解復雜判斷

  • 31天重構學習筆記25. 引入契約式設計

  • 31天重構學習筆記26. 避免雙重否定

  • 31天重構學習筆記27. 去除上帝類

  • 31天重構學習筆記28. 為布爾方法命名

  • 31天重構學習筆記29. 去除中間人對象

  • 31天重構學習筆記30. 盡快返回

  • 31天重構學習筆記31. 使用多態代替條件判斷

  • 代碼及PDF下載

1. 封裝集合

概念:本文所講的封裝集合就是把集合進行封裝,只提供調用端需要的接口。

正文:在很多時候,我們都不希望把一些不必要的操作暴露給調用端,只需要給它所需要的操作或數據就行,那么做法就是封裝。這個重構在微軟的代碼庫也經常遇到。比如最經典的屬性對字段的封裝就是一個很好的例子,那么下面我們將看到對集合的封裝,如下代碼所示,調用端只需要一個集合的信息,而我們則提供了一個IList的集合,大家都知道IList具有對集合的所有操作,所以這會帶來很多隱患,最好的做法就是對它進行重構。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.EncapsulateCollection.Before {public class Order{private List<OrderLine> _orderLines;private double _orderTotal;public IList<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);}}public class OrderLine{public double Total { get; private set; }} }

那么重構之后,我們把IList換成了IEnumerable,大家都知道只包括一個返回值為IEnumerator的GetEnumerator()方法,所以這樣只能遍歷取出它的值,而不能對這個集合做出改變,這正是我們所需要的結果,具體代碼如下:

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.EncapsulateCollection.After {public class Order{private List<OrderLine> _orderLines;private double _orderTotal;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);}}public class OrderLine{public double Total { get; private set; }} }

總結:這個例子很容易讓我們想到以前系統間耦合常喜歡用數據庫。每個系統都會操作數據庫,并且有些系統還會對數據庫的表結構或字段進行修改,那么這很容易就會造成維護的地獄,很明智的一個做法就是使用SOA來隔開這些耦合,讓一些只需要數據展示的系統得到自己需要的數據即可。

2. 移動方法

概念:本文所講的移動方法就是方法放在合適的位置(通常指放在合適的類中)。

正文:移動方法是一個很簡單也很常見的重構,只要是系統就會存在很多類,那么類里面包括很多方法,如果一個方法經常被另外一個類使用(比本身的類使用還多)或者這個方法本身就不應該放在這個類里面,那么這個適合應該考慮把它移到合適的類中。代碼如下:

namespace LosTechies.DaysOfRefactoring.MoveMethod.Before{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類的職責也單一,同時CalculateInterestRate也放到了經常使用且適合它的類中了,所以此重構是一個比較好的重構,能讓整個代碼變得更加合理。

namespace LosTechies.DaysOfRefactoring.MoveMethod.After {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;}} } namespace LosTechies.DaysOfRefactoring.MoveMethod.After {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; }} }

總結:這個重構法則在很多時候能讓我們把代碼組織的結構調整得更合理,同時也能給以后的維護帶來方便。


3. 提升方法

概念:提升方法是指將一個很多繼承類都要用到的方法提升到基類中。

正文:提升方法是指將一個很多繼承類都要用到的方法提升到基類中,這樣就能減少代碼量,同時讓類的結構更清晰。如下代碼所示,Turn方法在子類CarMotorcycle 都會用到,因為Vehicle都會有這個方法,所以我們就會想到把它提到基類中。

namespace LosTechies.DaysOfRefactoring.PullUpMethod.Before {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 Motorcycle都具有Turn這個方法,如果這個方法修改也只需要修改基類即可,所以給維護和以后的重構帶來了方便。

namespace LosTechies.DaysOfRefactoring.PullUpMethod.After {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. 降低方法

概念:本文中的降低方法和前篇的提升方法整好相反,也就是把個別子類使用到的方法從基類移到子類里面去。

正文:如下代碼所示,Animal 類中的方法Bark只有在其子類Dog中使用,所以最好的方案就是把這個方法移到子類Dog 中。

namespace LosTechies.DaysOfRefactoring.PushDownMethod.Before {public abstract class Animal{public void Bark(){// code to bark}}public class Dog : Animal{}public class Cat : Animal{} }

重構后的代碼如下,同時如果在父類Animal 中如果沒有其他的字段或者公用方法的話,可以考慮把Bark方法做成一個接口,從而去掉Animal類。

namespace LosTechies.DaysOfRefactoring.PushDownMethod.After {public abstract class Animal{}public class Dog : Animal{public void Bark(){// code to bark}}public class Cat : Animal{} }

總結:面向對象三大特征(繼承、封裝、多態)很多時候可以幫助我們,但同時也可能會造成使用過度或者使用不當,所以如何把握好設計,這個就變得至關重要。在什么時候使用繼承的方式,在什么時候使用組合和聚合,接口和繼承類的選擇等久成了我們的重點。


5. 提升字段

概念:本文中的提升字段和前面的提升方法頗為相似,就是把子類公用的字段提升到基類中,從而達到公用的目的。

正文:如下代碼所示, Account 的兩個子類CheckingAccountSavingsAccount 都有minimumCheckingBalance 字段,所以可以考慮把這個字段提到基類中。

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LosTechies.DaysOfRefactoring.PullUpField.Before {public abstract class Account{}public class CheckingAccount : Account{private decimal _minimumCheckingBalance = 5m;}public class SavingsAccount : Account{private decimal _minimumSavingsBalance = 5m;} }

重構后的代碼如下,這樣提的前提是這些子類有一個基類或者有很多相似的字段和方法,不然為了一個字段而單獨建立一個抽象類是不可取的,所以這個就需要具體權衡。

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LosTechies.DaysOfRefactoring.PullUpField.After {public abstract class Account{protected decimal _minimumBalance = 5m;}public class CheckingAccount : Account{}public class SavingsAccount : Account{} }

總結:這個重構的策略比較簡單,同時也是比較常用的一些做法,最主要就是要注意權衡是否真的有這個必要,看這樣做究竟有沒有什么好處(比如只需要改一個地方,維護簡便了,同時代碼量也更少了等)。


6. 降低字段

概念:本文中的降低字段和前篇的提升字段正好相反,就是把基類中只有某些少數類用到的字段降低到使用它們的子類中。

正文:如下代碼所示,基類Task 類中的_resolution字段只會在子類BugTask中用到,所以就考慮把它放到BugTask 類中。

namespace LosTechies.DaysOfRefactoring.PushDownField.Before {public abstract class Task{protected string _resolution;}public class BugTask : Task{}public class FeatureTask : Task{} }

重構后的代碼如下所示,這樣做的好處可以簡化基類,同時讓其他沒有使用它的子類也變得更加簡單,如果這樣的字段比較多的話,使用此重構也能節約一部分內存。

namespace LosTechies.DaysOfRefactoring.PushDownField.After {public abstract class Task{}public class BugTask : Task{private string _resolution;}public class FeatureTask : Task{} }

總結:此重構也是一個非常簡單的重構,在很多時候我們都會不自覺的使用它。


7. 重命名(方法,類,參數)

概念:本文中的改名(方法,類,參數)是指在寫代碼的時候對類、方法、參數、委托、事件等等元素取一個有意義的名稱。

正文:如下代碼所示,加入一個公司建立一個員工的類,類中有一個員工名字的字段和一個按照小時計算員工收入的方法,那么下面代碼的取名就顯得很難理解了,所以我們會重構名稱。

namespace LosTechies.DaysOfRefactoring.Rename.Before {public class Person{public string FN { get; set; }public decimal ClcHrlyPR(){// code to calculate hourly payratereturn 0m;}} }

重構后代碼如下所示,這樣看起來就非常清晰,如果有新進項目組的成員,也會變得很樂意看這個代碼。

namespace LosTechies.DaysOfRefactoring.Rename.After {// Changed the class name to Employeepublic class Employee{public string FirstName { get; set; }public decimal CalculateHourlyPay(){// code to calculate hourly payratereturn 0m;}} }

總結:此重構經常被廣大程序員所忽視,但是帶來的隱患是不可估量的,也許老板要修改功能,那我們來看這段沒有重構的代碼(就算是自己寫的,但由于時間和項目多等關系,我們也很難理解了),然后就會變得焦頭爛額。相反重構后的代碼就會覺得一目了然、賞心悅目。


8. 使用委派代替繼承

概念:本文中的“使用委派代替繼承”是指在根本沒有父子關系的類中使用繼承是不合理的,可以用委派的方式來代替。

如下代碼所示,Child Sanitation(公共設施)是沒有邏輯上的父子關系,因為小孩不可能是一個公共設施吧!所以我們為了完成這個功能可以考慮使用委派的方式。

namespace LosTechies.DaysOfRefactoring.ReplaceInheritance.Before {public class Sanitation{public string WashHands(){return "Cleaned!";}}public class Child : Sanitation{} }

重構后的代碼如下,把Sanitation 委派到Child類中,從而可以使用WashHands這個方法,這種方式我們經常會用到,其實IOC也使用到了這個原理,可以通過構造注入和方法注入等。

namespace LosTechies.DaysOfRefactoring.ReplaceInheritance.After {public class Sanitation{public string WashHands(){return "Cleaned!";}}public class Child{private Sanitation Sanitation { get; set; }public Child(){Sanitation = new Sanitation();}public string WashHands(){return Sanitation.WashHands();}} }

總結:這個重構是一個很好的重構,在很大程度上解決了濫用繼承的情況,很多設計模式也用到了這種思想(比如橋接模式、適配器模式、策略模式等)。


9. 提取接口

概念:本文中的“提取接口” 是指超過一個的類要使用某一個類中部分方法時,我們應該解開它們之間的依賴,讓調用者使用接口,這很容易實現也可以降低代碼的耦合性。

正文:如下代碼所示,RegistrationProcessor 類只使用到了Cla***egistration 類中的Create方法和Total 字段,所以可以考慮把他們做成接口給RegistrationProcessor調用。

namespace LosTechies.DaysOfRefactoring.ExtractInterface.Before {public class Cla***egistration{public void Create(){// create registration code}public void Transfer(){// class transfer code}public decimal Total { get; private set; }}public class RegistrationProcessor{public decimal Proce***egistration(Cla***egistration registration){registration.Create();return registration.Total;}} }

重構后的代碼如下,我們提取了一個ICla***egistration 接口,同時讓Cla***egistration繼承此接口,然后調用端RegistrationProcessor 就可以直接通過ICla***egistration接口進行調用。

namespace LosTechies.DaysOfRefactoring.ExtractInterface.After {public interface ICla***egistration{void Create();decimal Total { get; }}public class Cla***egistration : ICla***egistration{public void Create(){// create registration code}public void Transfer(){// class transfer code}public decimal Total { get; private set; }}public class RegistrationProcessor{public decimal Proce***egistration(ICla***egistration registration){registration.Create();return registration.Total;}} }

總結:這個重構策略也是一個常見的運用,很多設計模式也會在其中運用此思想(如簡單工程、抽象工廠等都會通過接口來解開依賴)。

10. 提取方法

概念:本文中的把某些計算復雜的過程按照功能提取成各個小方法,這樣就可以使代碼的可讀性、維護性得到提高。

正文:如下代碼所示,CalculateGrandTotal方法里面包含了多個邏輯,第一計算subTotal 的總和,第二subTotal 要循環減去discount,也就是計算Discounts,第三就是計算Tax。所以我們可以根據功能把他們拆分成三個小方法。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.ExtractMethod.Before {public class Receipt{private IList<decimal> Discounts { get; set; }private IList<decimal> ItemTotals { get; set; }public decimal CalculateGrandTotal(){decimal subTotal = 0m;foreach (decimal itemTotal in ItemTotals)subTotal += itemTotal;if (Discounts.Count > 0){foreach (decimal discount in Discounts)subTotal -= discount;}decimal tax = subTotal * 0.065m;subTotal += tax;return subTotal;}} }

重構后的代碼如下,然后CalculateGrandTotal方法就直接調用CalculateSubTotal、CalculateDiscounts、CalculateTax,從而是整個邏輯看起來更加清晰,并且可讀性和維護性也得到了大大提高。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.ExtractMethod.After {public class Receipt{private IList<decimal> Discounts { get; set; }private IList<decimal> ItemTotals { get; set; }public decimal CalculateGrandTotal(){decimal subTotal = CalculateSubTotal();subTotal = CalculateDiscounts(subTotal);subTotal = CalculateTax(subTotal);return subTotal;}private decimal CalculateTax(decimal subTotal){decimal tax = subTotal * 0.065m;subTotal += tax;return subTotal;}private decimal CalculateDiscounts(decimal subTotal){if (Discounts.Count > 0){foreach (decimal discount in Discounts)subTotal -= discount;}return subTotal;}private decimal CalculateSubTotal(){decimal subTotal = 0m;foreach (decimal itemTotal in ItemTotals)subTotal += itemTotal;return subTotal;}} }

總結:這個重構在很多公司都有一些的代碼規范作為參考,比如一個類不能超過多少行代碼,一個方法里面不能超過多少行代碼,這在一定程度上也能使程序員把這些復雜的邏輯剝離成意義很清楚的小方法。

11. 使用策略類

概念:本文中的“使用策略類” 是指用設計模式中的策略模式來替換原來的switch case和if else語句,這樣可以解開耦合,同時也使維護性和系統的可擴展性大大增強。

正文:如下面代碼所示,ClientCode 類會更加枚舉State的值來調用ShippingInfo的不同方法,但是這樣就會產生很多的判斷語句,如果代碼量加大,類變得很大了的話,維護中改動也會變得很大,每次改動一個地方,都要對整個結構進行編譯(假如是多個工程),所以我們想到了對它進行重構,剝開耦合。

namespace LosTechies.DaysOfRefactoring.SwitchToStrategy.Before {public class ClientCode{public decimal CalculateShipping(){ShippingInfo shippingInfo = new ShippingInfo();return shippingInfo.CalculateShippingAmount(State.Alaska);}}public enum State{Alaska,NewYork,Florida}public class ShippingInfo{public decimal CalculateShippingAmount(State shipToState){switch (shipToState){case State.Alaska:return GetAlaskaShippingAmount();case State.NewYork:return GetNewYorkShippingAmount();case State.Florida:return GetFloridaShippingAmount();default:return 0m;}}private decimal GetAlaskaShippingAmount(){return 15m;}private decimal GetNewYorkShippingAmount(){return 10m;}private decimal GetFloridaShippingAmount(){return 3m;}} }

重構后的代碼如下所示,抽象出一個IShippingCalculation 接口,然后把ShippingInfo類里面的GetAlaskaShippingAmount、GetNewYorkShippingAmount、GetFloridaShippingAmount三個方法分別提煉成三個類,然后繼承自IShippingCalculation接口,這樣在調用的時候就可以通過IEnumerable<IShippingCalculation> 來解除之前的switch case語句,這和IOC的做法頗為相似。

using System; using System.Collections.Generic; using System.Linq; namespace LosTechies.DaysOfRefactoring.SwitchToStrategy.After_WithIoC {public interface IShippingInfo{decimal CalculateShippingAmount(State state);}public class ClientCode{[Inject]public IShippingInfo ShippingInfo { get; set; }public decimal CalculateShipping(){return ShippingInfo.CalculateShippingAmount(State.Alaska);}}public enum State{Alaska,NewYork,Florida}public class ShippingInfo : IShippingInfo{private IDictionary<State, IShippingCalculation> ShippingCalculations { get; set; }public ShippingInfo(IEnumerable<IShippingCalculation> shippingCalculations){ShippingCalculations = shippingCalculations.ToDictionary(calc => calc.State);}public decimal CalculateShippingAmount(State shipToState){return ShippingCalculations[shipToState].Calculate();}}public interface IShippingCalculation{State State { get; }decimal Calculate();}public class AlaskShippingCalculation : IShippingCalculation{public State State { get { return State.Alaska; } }public decimal Calculate(){return 15m;}}public class NewYorkShippingCalculation : IShippingCalculation{public State State { get { return State.NewYork; } }public decimal Calculate(){return 10m;}}public class FloridaShippingCalculation : IShippingCalculation{public State State { get { return State.Florida; } }public decimal Calculate(){return 3m;}} }

總結:這種重構在設計模式當中把它單獨取了一個名字——策略模式,這樣做的好處就是可以隔開耦合,以注入的形式實現功能,這使增加功能變得更加容易和簡便,同樣也增強了整個系統的穩定性和健壯性。

12. 分解依賴

概念:本文中的“分解依賴” 是指對部分不滿足我們要求的類和方法進行依賴分解,通過裝飾器來達到我們需要的功能。

正文:正如下面代碼所示,如果你要在你的代碼中加入單元測試但有一部分代碼是你不想測試的,那么你應用使用這個的重構。下面的例子中我們應用靜態類來完成某些工作,但問題是在單元測試時我們無法mock靜態類,所以我們只能引入靜態類的裝飾接口來分解對靜態類的依賴。從而我們使我們的調用類只需要依賴于裝飾接口就能完成這個操作。

namespace LosTechies.DaysOfRefactoring.BreakDependencies.Before {public class AnimalFeedingService{private bool FoodBowlEmpty { get; set; }public void Feed(){if (FoodBowlEmpty)Feeder.ReplenishFood();// more code to feed the animal}}public static class Feeder{public static void ReplenishFood(){// fill up bowl}} }

重構后代碼如下,我們添加一個接口和一個實現類,在實現類中調用靜態類的方法,所以說具體做什么事情沒有改變,改變的只是形式,但這樣做的一個好處是增加了了代碼的可測試性。在應用了分解依賴模式后,我們就可以在單元測試的時候mock一個IFeederService對象并通過AnimalFeedingService的構造函數傳遞給它。這樣就可以完成我們需要的功能。

namespace LosTechies.DaysOfRefactoring.BreakDependencies.After {public class AnimalFeedingService{public IFeederService FeederService { get; set; }public AnimalFeedingService(IFeederService feederService){FeederService = feederService;}private bool FoodBowlEmpty { get; set; }public void Feed(){if (FoodBowlEmpty)FeederService.ReplenishFood();// more code to feed the animal}}public interface IFeederService{void ReplenishFood();}public class FeederService : IFeederService{public void ReplenishFood(){Feeder.ReplenishFood();}}public static class Feeder{public static void ReplenishFood(){// fill up bowl}} }

總結:這個重構在很多時候和設計模式中的一些思想類似,使用中間的裝飾接口來分解兩個類之間的依賴,對類進行裝飾,然后使它滿足我們所需要的功能。

13. 提取方法對象

概念:本文中的“提取方法對象”是指當你發現一個方法中存在過多的局部變量時,你可以通過使用“提取方法對象”重構來引入一些方法,每個方法完成任務的一個步驟,這樣可以使得程序變得更具有可讀性。

正文:如下代碼所示,Order 類中的Calculate方法要完成很多功能,在之前我們用“提取方法”來進行重構,現在我們采取“提取方法對象”來完成重構。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.ExtractMethodObject.Before {public class OrderLineItem{public decimal Price { get; private set; }}public class Order{private IList<OrderLineItem> OrderLineItems { get; set; }private IList<decimal> Discounts { get; set; }private decimal Tax { get; set; }public decimal Calculate(){decimal subTotal = 0m;// Total up line itemsforeach (OrderLineItem lineItem in OrderLineItems){subTotal += lineItem.Price;}// Subtract Discountsforeach (decimal discount in Discounts)subTotal -= discount;// Calculate Taxdecimal tax = subTotal * Tax;// Calculate GrandTotaldecimal grandTotal = subTotal + tax;return grandTotal;}} }

正如下代碼所示,我們引入了OrderCalculator類,該類實現了所有的計算方法,Order類將自身傳遞給 OrderCalculator類并調用Calculate方法完成計算過程。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.ExtractMethodObject.After {public class OrderLineItem{public decimal Price { get; private set; }}public class Order{public IEnumerable<OrderLineItem> OrderLineItems { get; private set; }public IEnumerable<decimal> Discounts { get; private set; }public decimal Tax { get; private set; }public decimal Calculate(){return new OrderCalculator(this).Calculate();}}public class OrderCalculator{private decimal SubTotal { get; set; }private IEnumerable<OrderLineItem> OrderLineItems { get; set; }private IEnumerable<decimal> Discounts { get; set; }private decimal Tax { get; set; }public OrderCalculator(Order order){OrderLineItems = order.OrderLineItems;Discounts = order.Discounts;Tax = order.Tax;}public decimal Calculate(){CalculateSubTotal();SubtractDiscounts();CalculateTax();return SubTotal;}private void CalculateSubTotal(){// Total up line itemsforeach (OrderLineItem lineItem in OrderLineItems)SubTotal += lineItem.Price;}private void SubtractDiscounts(){// Subtract Discountsforeach (decimal discount in Discounts)SubTotal -= discount;}private void CalculateTax(){// Calculate TaxSubTotal += SubTotal * Tax;}} }

總結:本文的重構方法在有的時候還是比較有用,但這樣會造成字段的增加,同時也會帶來一些維護的不便,它和“提取方法”最大的區別就是一個通過方法返回需要的數據,另一個則是通過字段來存儲方法的結果值,所以在很大程度上我們都會選擇“提取方法”。

14. 分離職責

概念:本文中的“分離職責”是指當一個類有許多職責時,將部分職責分離到獨立的類中,這樣也符合面向對象的五大特征之一的單一職責原則,同時也可以使代碼的結構更加清晰,維護性更高。

正文:如下代碼所示,Video類有兩個職責,一個是處理video rental,另一個是計算每個客戶的總租金。我們可以將這兩個職責分離出來,因為計算每個客戶的總租金可以在Customer計算,這也比較符合常理。

using System.Collections.Generic;using System.Linq;namespace LosTechies.DaysOfRefactoring.BreakResponsibilities.Before{public class Video{public void PayFee(decimal fee) { }public void RentVideo(Video video, Customer customer) { customer.Videos.Add(video); }public decimal CalculateBalance(Customer customer) { returncustomer.LateFees.Sum(); } }public class Customer{public IList<decimal> LateFees { get; set; }public IList<Video> Videos { get; set; } }}

重構后的代碼如下,這樣Video 的職責就變得很清晰,同時也使代碼維護性更好。

using System.Collections.Generic;using System.Linq;namespace LosTechies.DaysOfRefactoring.BreakResponsibilities.After{public class Video{public void RentVideo(Video video, Customer customer) { customer.Videos.Add(video); } }public class Customer{public IList<decimal> LateFees { get; set; }public IList<Video> Videos { get; set; }public void PayFee(decimal fee) { }public decimal CalculateBalance(Customer customer) {return customer.LateFees.Sum(); } }}

總結:這個重構經常會用到,它和之前的“移動方法”有幾分相似之處,讓方法放在合適的類中,并且簡化類的職責,同時這也是面向對象五大原則之一和設計模式中的重要思想。

15. 移除重復內容

概念:本文中的“移除重復內容”是指把一些很多地方都用到的邏輯提煉出來,然后提供給調用者統一調用。

正文:如下代碼所示,ArchiveRecord和CloseRecord都會用到Archived = true; 和DateArchived = DateTime.Now; 這兩條語句,所以我們就可以對它進行重構。

using System; namespace LosTechies.DaysOfRefactoring.RemoveDuplication.Before {public class MedicalRecord{public DateTime DateArchived { get; private set; }public bool Archived { get; private set; }public void ArchiveRecord(){Archived = true;DateArchived = DateTime.Now;}public void CloseRecord(){Archived = true;DateArchived = DateTime.Now;}} }

重構后的代碼如下所示,我們提煉了SwitchToArchived方法來封裝公用的操作,然后給ArchiveRecord和CloseRecord統一調用。

using System; namespace LosTechies.DaysOfRefactoring.RemoveDuplication.After {public class MedicalRecord{public DateTime DateArchived { get; private set; }public bool Archived { get; private set; }public void ArchiveRecord(){SwitchToArchived();}public void CloseRecord(){SwitchToArchived();}private void SwitchToArchived(){Archived = true;DateArchived = DateTime.Now;}} }

總結:這個重構很簡單,絕大多數程序員都會使用這種重構方法,但有時由于習慣、時間、趕進度等原因而忽略它,所以會使得整個系統雜亂無章,到處都是Ctrl+C和Ctrl+V的痕跡。

16. 封裝條件

概念:本文中的“封裝條件”是指條件關系比較復雜時,代碼的可讀性會比較差,所以這時我們應當根據條件表達式是否需要參數將條件表達式提取成可讀性更好的屬性或者方法,如果條件表達式不需要參數則可以提取成屬性,如果條件表達式需要參數則可以提取成方法。

正文:如下代碼所示,PerformCoolFunction里面的if條件判斷比較復雜,看起來有點雜亂,所以就把它提出來。

using System; namespace LosTechies.DaysOfRefactoring.EncapsulateConditional.Before {public class RemoteControl{private string[] Functions { get; set; }private string Name { get; set; }private int CreatedYear { get; set; }public string PerformCoolFunction(string buttonPressed){// Determine if we are controlling some extra function // that requires special conditionsif (Functions.Length > 1 && Name == "RCA" && CreatedYear > DateTime.Now.Year - 2)return "doSomething";}} }

如下代碼所示,我們把條件表達式封裝成HasExtraFunctions屬性,這樣先前的條件判斷就成了if (HasExtraFunctions) ,所以這樣就在很大程度上提高了可讀性。

using System; namespace LosTechies.DaysOfRefactoring.EncapsulateConditional.After {public class RemoteControl{private string[] Functions { get; set; }private string Name { get; set; }private int CreatedYear { get; set; }private bool HasExtraFunctions{get { return Functions.Length > 1 && Name == "RCA" && CreatedYear > DateTime.Now.Year - 2; }}public string PerformCoolFunction(string buttonPressed){// Determine if we are controlling some extra function // that requires special conditionsif (HasExtraFunctions)return "doSomething";}} }

總結:這個重構在很大程度上能改善代碼的可讀性,尤其是在一個邏輯很復雜的應用中,把這些條件判斷封裝成一個有意義的名字,這樣很復雜的邏輯也會立刻變得簡單起來。

17. 提取父類

概念:本文中的“提取父類”是指類中有一些字段或方法,你想把它們提取到父類中以便同一繼承層次的其它類也可以訪問他們,這個和之前的很多重構有異曲同工之處。

正文:Dog 類中的EatFood和Groom有可能被其他類用到,因為他們都是動物的一些公有性質,所以這個時候我們就會考慮對它進行提煉。

namespace LosTechies.DaysOfRefactoring.ExtractSuperclass.Before{ public class Dog { public void EatFood() { // eat some food } public void Groom() { // perform grooming } } }

代碼如下所示,提取了Animal 方法來封裝公用的EatFood和Groom類,從而使其他繼承了Animal 類的子類都可以使用這兩個方法了。

namespace LosTechies.DaysOfRefactoring.ExtractSuperclass.After {public class Animal{public void EatFood(){// eat some food}public void Groom(){// perform grooming}}public class Dog : Animal{} }

總結:這個重構是典型的繼承用法,很多程序員都會選擇這樣做,但是要注意正確的使用,不要造成過度使用了繼承,如果過度使用了,請考慮用接口、組合和聚合來實現。

18. 使用條件判斷代替異常

概念:本文中的“使用條件判斷代替異常”是指把沒有必要使用異常做判斷的條件盡量改為條件判斷。

正文:如下代碼所示,在日常的編碼中我們經常需要用到異常來控制程序流,Start方法里面用trycatch 做條件判斷,我們知道這里沒有必要使用這種方式,因為你不需要做類型不可控的類型轉換,也不需要處理異常行為,所以我們應該對它進行重構。

namespace LosTechies.DaysOfRefactoring.ReplaceException.Before {public class Microwave{private IMicrowaveMotor Motor { get; set; }public bool Start(object food){bool foodCooked = false;try{Motor.Cook(food);foodCooked = true;}catch (InUseException){foodcooked = false;}return foodCooked;}} }

重構后的代碼如下所示,try catch做條件判斷的語句改成了if return的方式,這樣在很多程度上統一了代碼的書寫,同時也提高了性能。

namespace LosTechies.DaysOfRefactoring.ReplaceException.After {public class Microwave{private IMicrowaveMotor Motor { get; set; }public bool Start(object food){if (Motor.IsInUse)return false;Motor.Cook(food);return true;}} }

總結: 這個重構在項目代碼中也經常用到,因為對于一部分程序員,是很難把握什么時候用trycatch ,什么地方該用trycatch 。記得之前大家還專門討論過這些,比如如何用好以及在大中型項目中應該把它放在哪一個組件中等。

19. 提取工廠類

概念:本文中的“提取工廠類”是指如果要創建的對象很多,則代碼會變的很復雜。一種很好的方法就是提取工廠類。

正文:一般來說我們需要在代碼中設置一些對象,以便獲得它們的狀態,從而使用對象,所謂的設置通常來說就是創建對象的實例并調用對象的方法。有時如果要創建的對象很多,則代碼會變的很復雜。這便是工廠模式發揮作用的情形。工廠模式的復雜應用是使用抽象工廠創建對象集,但我們在這里只是使用基本的工廠類創建對象的一個簡單應用。

如下代碼所示,New方法包含創建類的整個邏輯,如果現在要創建的類比較多而且邏輯比較復雜的話(如根據不同條件創建對象,什么時候創建對象),我們的New方法邏輯會變得很大,同時代碼也變得很難維護。所以我們就會采用提取工廠類的方式進行提煉。

namespace LosTechies.DaysOfRefactoring.ExtractServiceClass.Before{public class PoliceCarController{public PoliceCar New(int mileage, bool serviceRequired) { PoliceCar policeCar = new PoliceCar(); policeCar.ServiceRequired = serviceRequired; policeCar.Mileage = mileage;return policeCar; } }}

那么重構后的代碼如下,New方法變得很簡單了,指需要調用實現接IPoliceCarFactory 接口的PoliceCarFactory 類就可以返回對象,這樣就隔開了創建對象的邏輯,如果需求現在變為根據不同的條件創建不同的對象,什么時候創建對象等都變成了比較簡單的事情,在后期可以把對象都配置在XML里面,使用反射的方式實現IOC注入創建。

namespace LosTechies.DaysOfRefactoring.ExtractServiceClass.After {public interface IPoliceCarFactory{PoliceCar Create(int mileage, bool serviceRequired);}public class PoliceCarFactory : IPoliceCarFactory{public PoliceCar Create(int mileage, bool serviceRequired){PoliceCar policeCar = new PoliceCar();policeCar.ReadForService = serviceRequired;policeCar.Mileage = mileage;return policeCar;}}public class PoliceCarController{public IPoliceCarFactory PoliceCarFactory { get; set; }public PoliceCarController(IPoliceCarFactory policeCarFactory){PoliceCarFactory = policeCarFactory;}public PoliceCar New(int mileage, bool serviceRequired){return PoliceCarFactory.Create(mileage, serviceRequired);}} }

總結:這個重構經常會在項目中使用,如果要創建的對象是一個,你可以采用簡單工廠,但是這種方式還是會存在很多依賴,維護起來也比較不方便。所以推薦使用工廠方法模式,把實例化延遲到子類。如果你要創建一系列的對象,那么就推薦你使用抽象工廠模式,但是要注意不要過度設計,只要能滿足不斷變化的需求和給以后的維護和重構帶來方便即可。

20. 提取子類

概念:本文中的”提取子類”是指把基類中的一些不是所有子類都需要訪問的方法調整到子類中。

正文:當你的基類中存在一些方法不是所有的子類都需要訪問,你想將它們調整到子類中時,這個重構會變得很有用了。如下代碼所示,我們需要一個 Registration類用來處理學生選課的信息。但是當Registration類開始工作后,我們意識到我們會在兩種不同的上下文中使用Registration類,NonRegistrationAction和Notes只有在我們處理未注冊情況下才用到。

所以我們將NonRegistration和Notes提到單獨的NonRegistration類中。 using System; namespace LosTechies.DaysOfRefactoring.SampleCode.ExtractSubclass.Before {public class Registration{public NonRegistrationAction Action { get; set; }public decimal RegistrationTotal { get; set; }public string Notes { get; set; }public string Description { get; set; }public DateTime RegistrationDate { get; set; }} }

重構后的代碼如下所示,這樣也滿足面向對象五大原則之一的單一職責。同時也讓類的結構變得更加清晰,增強了可維護性。

using System; namespace LosTechies.DaysOfRefactoring.SampleCode.ExtractSubclass.After {public class Registration{public decimal RegistrationTotal { get; set; }public string Description { get; set; }public DateTime RegistrationDate { get; set; }}public class NonRegistration : Registration{public NonRegistrationAction Action { get; set; }public string Notes { get; set; }} }

總結:這個重構方法經常用來規范類的職責,和之前的一些重構方法也有些類似。

21. 合并繼承

概念:本文中的”合并繼承”是指如果子類的屬性和方法也適合于基類,那么就可以移除子類,從而減少依賴關系。

正文:上一篇我們講到“提取子類”重構是指當基類中的一個責任不被所有的子類所需要時,將這些責任提取到合適的子類中。而我們今天所要講的的“合并繼承”重構一般用在當我們覺得不需要子類的時候。

如下代碼所示,StudentWebSite子類除了有一個屬性用來說明網站是否是活動的外沒有別的責任,在這種情形下我們意識到IsActive屬性可以應用到所有的網站,所以我們可以將IsActive屬性上移到基類中,并去掉StudentWebSite類。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.SampleCode.CollapseHierarchy.Before {public class Website{public string Title { get; set; }public string Description { get; set; }public IEnumerable<Webpage> Pages { get; set; }}public class StudentWebsite : Website{public bool IsActive { get; set; }} } 重構后的代碼如下: using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.SampleCode.CollapseHierarchy.After {public class Website{public string Title { get; set; }public string Description { get; set; }public IEnumerable<Webpage> Pages { get; set; }public bool IsActive { get; set; }} }

總結: 這篇和上篇其實最主要論述了子類和父類的繼承關系以及如何判斷什么時候需要使用繼承,一般我們都能處理好這些關系,所以相對比較簡單。

22. 分解方法

概念:本文中的”分解方法”是指把我們所做的這個功能不停的分解方法,直到將一個大方法分解為名字有意義且可讀性更好的若干個小方法。

正文:如下代碼所示,因為現實中AcceptPayment方法不會做這么多的事情。,所以我們通過幾次分解將 AcceptPayment拆分成若干個名字有意義且可讀性更好的小方法。

using System.Collections.Generic; using System.Linq; namespace LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.Before {public class CashRegister{public CashRegister(){Tax = 0.06m;}private decimal Tax { get; set; }public void AcceptPayment(Customer customer, IEnumerable<Product> products, decimal payment){decimal subTotal = 0m;foreach (Product product in products){subTotal += product.Price;}foreach (Product product in products){subTotal -= product.AvailableDiscounts;}decimal grandTotal = subTotal * Tax;customer.DeductFromAccountBalance(grandTotal);}}public class Customer{public void DeductFromAccountBalance(decimal amount){// deduct from balance}}public class Product{public decimal Price { get; set; }public decimal AvailableDiscounts { get; set; }} }

重構后的代碼如下,我們把AcceptPayment的內部邏輯拆分成了CalculateSubtotal、SubtractDiscounts、AddTax、SubtractFromCustomerBalance四個功能明確且可讀性更好的小方法。

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After {public class CashRegister{public CashRegister(){Tax = 0.06m;}private decimal Tax { get; set; }private IEnumerable<Product> Products { get; set; }public void AcceptPayment(Customer customer, IEnumerable<Product> products, decimal payment){decimal subTotal = CalculateSubtotal();subTotal = SubtractDiscounts(subTotal);decimal grandTotal = AddTax(subTotal);SubtractFromCustomerBalance(customer, grandTotal);}private void SubtractFromCustomerBalance(Customer customer, decimal grandTotal){customer.DeductFromAccountBalance(grandTotal);}private decimal AddTax(decimal subTotal){return subTotal * Tax;}private decimal SubtractDiscounts(decimal subTotal){foreach (Product product in Products){subTotal -= product.AvailableDiscounts;}return subTotal;}private decimal CalculateSubtotal(){decimal subTotal = 0m;foreach (Product product in Products){subTotal += product.Price;}return subTotal;}}public class Customer{public void DeductFromAccountBalance(decimal amount){// deduct from balance}}public class Product{public decimal Price { get; set; }public decimal AvailableDiscounts { get; set; }} }

總結:其實這個重構和我們前面講的“提取方法”和“提取方法對象”如出一轍,尤其是“提取方法”,所以大家只要知道用這種思想重構就行。

23. 引入參數對象

概念:本文中的“引入參數對象”是指當一個方法的參數過多或者過為復雜時,可以考慮把這些參數封裝成一個單獨的類。

正文:如果一個方法所需要的參數大于5個,理解該方法的簽名就變得比較困難,因為這樣感覺參數很長、樣式不好并且沒有分類,所以我們有必要把參數進行封裝。

namespace LosTechies.DaysOfRefactoring.SampleCode.ParameterObject.Before {public class Registration{public void Create(decimal amount, Student student, IEnumerable<Course> courses, decimal credits){// do work}} }

通常這種情形下創建一個用戶傳遞參數的類是很有幫助的,這會使得代碼更容易明白也更靈活,因為當你需要增加參數時,只需要給參數類添加一個屬性即可。請注意只有當你發現方法的參數比較多時才應該應用該重構,如果方法的參數比較少,就沒有必要應用此重構,因為該重構會增加系統中類的數量,同時也會加大維護負擔。所以要看參數情況而定。
重構后的代碼如下:

using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.SampleCode.ParameterObject.After {public class RegistrationContext{public decimal Amount { get; set; }public Student Student { get; set; }public IEnumerable<Course> Courses { get; set; }public decimal Credits { get; set; }}public class Registration{public void Create(RegistrationContext registrationContext){// do work}} }

總結:這種重構很重要,尤其是當一個方法的參數比較多的時候,不管是大中型項目還是小型項目,都會遇到這種場景,所以建議大家多使用這個重構。這種封裝的思想在SOA 里面也經常運用到,封裝輸入Message,封裝輸出Message,消息來和消息去以及消息間的交互就構成了整個應用體系。

24. 分解復雜判斷

概念:本文中的”分解復雜判斷”是指把原來復雜的條件判斷等語句用盡快返回等方式簡化代碼。

正文:簡單的來說,當你的代碼中有很深的嵌套條件時,花括號就會在代碼中形成一個長長的箭頭。我們經常在不同的代碼中看到這種情況,并且這種情況也會擾亂代碼的可讀性。

如下代碼所示,HasAccess方法里面包含一些嵌套條件,如果再加一些條件或者增加復雜度,那么代碼就很可能出現幾個問題:1,可讀性差。 2,很容易出現異常。 3,性能較差。

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LosTechies.DaysOfRefactoring.SampleCode.ArrowheadAntipattern.Before {public class Security{public ISecurityChecker SecurityChecker { get; set; }public Security(ISecurityChecker securityChecker){SecurityChecker = securityChecker;}public bool HasAccess(User user, Permission permission, IEnumerable<Permission> exemptions){bool hasPermission = false;if (user != null){if (permission != null){if (exemptions.Count() == 0){if (SecurityChecker.CheckPermission(user, permission) || exemptions.Contains(permission)){hasPermission = true;}}}}return hasPermission;}} }

那么重構上面的代碼也很簡單,如果有可能的話,盡量將條件從方法中移除,我們讓代碼在做處理任務之前先檢查條件,如果條件不滿足就盡快返回,不繼續執行。下面是重構后的代碼:

using System.Collections.Generic; using System.Linq; namespace LosTechies.DaysOfRefactoring.SampleCode.ArrowheadAntipattern.After {public class Security{public ISecurityChecker SecurityChecker { get; set; }public Security(ISecurityChecker securityChecker){SecurityChecker = securityChecker;}public bool HasAccess(User user, Permission permission, IEnumerable<Permission> exemptions){if (user == null || permission == null)return false;if (exemptions.Contains(permission))return true;return SecurityChecker.CheckPermission(user, permission);}} }

總結:這個重構很重要,它和后面講的”盡快返回“有些類似,我們在做復雜的處理過程時,要經常考慮這個重構,用好了它,會對我們的幫助很大。

25. 引入契約式設計

概念:本文中的”引入契約式設計”是指我們應該對應該對輸入和輸出進行驗證,以確保系統不會出現我們所想象不到的異常和得不到我們想要的結果。

正文:契約式設計規定方法應該對輸入和輸出進行驗證,這樣你便可以保證你得到的數據是可以工作的,一切都是按預期進行的,如果不是按預期進行,異常或是錯誤就應該被返回,下面我們舉的例子中,我們方法中的參數可能會值為null的情況,在這種情況下由于我們沒有驗證,NullReferenceException異常會報出。另外在方法的結尾處我們也沒有保證會返回一個正確的decimal值給調用方法的對象。

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LosTechies.DaysOfRefactoring.SampleCode.Day25_DesignByContract {public class CashRegister{public decimal TotalOrder(IEnumerable<Product> products, Customer customer){decimal orderTotal = products.Sum(product => product.Price);customer.Balance += orderTotal;return orderTotal;}} }

對上面的代碼重構是很簡單的,首先我們處理不會有一個null值的customer對象,檢查我們最少會有一個product對象。在返回訂單總和之前先確保我們會返回一個有意義的值。如果上面說的檢查有任何一個失敗,我們就拋出對應的異常,并在異常里說明錯誤的詳細信息,而不是直接拋出NullReferenceException。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Contracts; namespace LosTechies.DaysOfRefactoring.SampleCode.DesignByContract.After {public class CashRegister{public decimal TotalOrder(IEnumerable<Product> products, Customer customer){if (customer == null)throw new ArgumentNullException("customer", "Customer cannot be null");if (products.Count() == 0)throw new ArgumentException("Must have at least one product to total", "products");decimal orderTotal = products.Sum(product => product.Price);customer.Balance += orderTotal;if (orderTotal == 0)throw new ArgumentOutOfRangeException("orderTotal", "Order Total should not be zero");return orderTotal;}} }

上面的代碼中添加了額外的代碼來進行驗證,雖然看起來代碼復雜度增加了,但我認為這是非常值得做的,因為當NullReferenceException發生時去追查異常的詳細信息真是很令人討厭的事情。

總結:微軟在處理代碼乃至產品的時候,很喜歡應用此重構,你如果認真看它的代碼庫,認真看一下WCF的設計,就不難發現了。這個重構建議大家經常使用,這會增強整個系統的穩定性和健壯性。

26. 避免雙重否定

概念:本文中的“避免雙重否定”是指把代碼中的雙重否定語句修改成簡單的肯定語句,這樣即讓代碼可讀,同時也給維護帶來了方便。

正文:避免雙重否定重構本身非常容易實現,但我們卻在太多的代碼中見過因為雙重否定降低了代碼的可讀性以致于非常讓人容易誤解真正意圖。存在雙重否定的代碼具有非常大的危害性,因為這種類型的代碼容易引起錯誤的假設,錯誤的假設又會導致書寫出錯誤的維護代碼,最終會導致bug產生。具體可以看下面的代碼:

using System.Collections.Generic; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; namespace LosTechies.DaysOfRefactoring.SampleCode.DoubleNegative.Before {public class Order{public void Checkout(IEnumerable<Product> products, Customer customer){if (!customer.IsNotFlagged){// the customer account is flagged // log some errors and returnreturn;}// normal order processing}}public class Customer{public decimal Balance { get; private set; }public bool IsNotFlagged{get { return Balance < 30m; }}} } 如上代碼中的雙重否定可讀性非常低,因為我們很難搞明白雙重否定的正確值。要重構它也非常容易,如下是重構后的代碼: using System.Collections.Generic; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; namespace LosTechies.DaysOfRefactoring.SampleCode.DoubleNegative.After {public class Order{public void Checkout(IEnumerable<Product> products, Customer customer){if (customer.IsFlagged){// the customer account is flagged // log some errors and returnreturn;}// normal order processing}}public class Customer{public decimal Balance { get; private set; }public bool IsFlagged{get { return Balance >= 30m; }}} }

總結: “雙重否定”很容易讓人產生錯誤的判斷,也很難讓人理解你的代碼,所以這個重構在我們的代碼中是很重要的,尤其是在判斷條件很多且業務復雜的時候。

27. 去除上帝類

概念:本文中的“去除上帝類”是指把一個看似功能很強且很難維護的類,按照職責把自己的屬性或方法分派到各自的類中或分解成功能明確的類,從而去掉上帝類。

正文:我們經常可以在一些原來的代碼中見到一些類明確違反了SRP原則(單一原則),這些類通常以“Utils”或“Manager”后綴結尾,但有時這些類也沒有這些特征,它僅僅是多個類多個方法的組合。另一個關于上帝類的特征是通常這些類中的方法被用注釋分隔為不同的分組。那么久而久之,這些類被轉換為那些沒有人愿意進行歸并到合適類的方法的聚集地,對這些類進行重構是將類中的代碼按照職責分派到各自的類中,這樣就解除了上帝類,也減輕了維護的負擔。

using System.Collections.Generic; using LosTechies.DaysOfRefactoring.EncapsulateCollection.After; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; using Customer = LosTechies.DaysOfRefactoring.BreakResponsibilities.After.Customer; namespace LosTechies.DaysOfRefactoring.SampleCode.RemoveGodClasses.Before {public class CustomerService{public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer){// do work}public bool CustomerIsValid(Customer customer, Order order){// do work}public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer){// do work}public void Register(Customer customer){// do work}public void ForgotPassword(Customer customer){// do work}} } 我們看到要重構上面的代碼是很簡單的,只要將相關的方法按職責分派到對應的類中即可,帶來的好處就是這會降低代碼的顆粒度并減少未來維護代碼的成本。下面是重構后的代碼,它將上面 的代碼按照職責分為了兩個不同的類。 using System.Collections.Generic; using LosTechies.DaysOfRefactoring.EncapsulateCollection.After; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; using Customer = LosTechies.DaysOfRefactoring.BreakResponsibilities.After.Customer; namespace LosTechies.DaysOfRefactoring.SampleCode.RemoveGodClasses.After {public class CustomerOrderService{public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer){// do work}public bool CustomerIsValid(Customer customer, Order order){// do work}public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer){// do work}}public class CustomerRegistrationService{public void Register(Customer customer){// do work}public void ForgotPassword(Customer customer){// do work}} }

總結: “去除上帝類”是我們經常容易造成的,第一是因為簡便,看到有一個現成的類,大家都會喜歡把代碼往里面寫,最后導致越寫越大,并且聲明功能都有,這樣即降低了可讀性,也造成了維護的負擔。

28. 為布爾方法命名

概念:本文中的“為布爾方法命名”是指如果一個方法帶有大量的bool 參數時,可以根據bool 參數的數量,提取出若干個獨立的方法來簡化參數。

正文:我們現在要說的重構并不是普通字面意義上的重構,它有很多值得討論的地方。當一個方法帶有大量的bool參數時,會導致方法很容易被誤解并產生非預期的行為,

根據布爾型參數的數量,我們可以決定提取出若干個獨立的方法來。具體代碼如下:

using LosTechies.DaysOfRefactoring.BreakResponsibilities.After; namespace LosTechies.DaysOfRefactoring.SampleCode.RenameBooleanMethod.Before {public class BankAccount{public void CreateAccount(Customer customer, bool withChecking, bool withSavings, bool withStocks){// do work}} } 我們可以將上面的bool參數以獨立方法的形式暴露給調用端以提高代碼的可讀性,同時我們還需要將原來的方法改為private以限制其可訪問性。顯然我們關于要 提取的獨立方法會有一個很大的排列組合,這是一大缺點,所以我們可以考慮引入”參數對象“重構。 using LosTechies.DaysOfRefactoring.BreakResponsibilities.After; namespace LosTechies.DaysOfRefactoring.SampleCode.RenameBooleanMethod.After {public class BankAccount{public void CreateAccountWithChecking(Customer customer){CreateAccount(customer, true, false);}public void CreateAccountWithCheckingAndSavings(Customer customer){CreateAccount(customer, true, true);}private void CreateAccount(Customer customer, bool withChecking, bool withSavings){// do work}} }

總結: “為布爾方法命名”這個重構在很多時候都不常用,如果用戶的參數可枚舉,我們一般會枚舉它的值,不過使用這種重構也有好處,就是分解開來以后,方法多了,參數少了,代碼維護起來方便了一些。

29. 去除中間人對象

概念:本文中的“去除中間人對象”是指把 在中間關聯而不起任何其他作用的類移除,讓有關系的兩個類直接進行交互。

正文:有些時候在我們的代碼會存在一些“幽靈類”,設計模式大師Fowler稱它們為“中間人”類,“中間人”類除了調用別的對象之外不做任何事情,所以“中間人”類沒有存在的必要,我們可以將它們從代碼中刪除,從而讓交互的兩個類直接關聯。

如下代碼所示,Consumer 類要得到AccountDataProvider的數據,但中間介入了沒起任何作用的 AccountManager 類來關聯,所以我們應當移除。

using LosTechies.DaysOfRefactoring.PullUpField.After; namespace LosTechies.DaysOfRefactoring.SampleCode.RemoveMiddleMan.Before {public class Consumer{public AccountManager AccountManager { get; set; }public Consumer(AccountManager accountManager){AccountManager = accountManager;}public void Get(int id){Account account = AccountManager.GetAccount(id);}}public class AccountManager{public AccountDataProvider DataProvider { get; set; }public AccountManager(AccountDataProvider dataProvider){DataProvider = dataProvider;}public Account GetAccount(int id){return DataProvider.GetAccount(id);}}public class AccountDataProvider{public Account GetAccount(int id){// get account}} } 重構后的代碼如下所示,Consumer AccountDataProvider 直接進行關聯,這樣代碼就簡單了。 using LosTechies.DaysOfRefactoring.PullUpField.After; namespace LosTechies.DaysOfRefactoring.SampleCode.RemoveMiddleMan.After {public class Consumer{public AccountDataProvider AccountDataProvider { get; set; }public Consumer(AccountDataProvider dataProvider){AccountDataProvider = dataProvider;}public void Get(int id){Account account = AccountDataProvider.GetAccount(id);}}public class AccountDataProvider{public Account GetAccount(int id){// get account}} }

總結: “去除中間人對象”很多時候都會很有作用,尤其是在誤用設計模式的代碼中最容易見到,設計模式中的適配器模式和代理模式等都用中間的類是兩者進行關聯,這是比較合理的,因為中間類做了很多事情,而對于沒有任何作用的中間類應該移除。

30. 盡快返回

概念: 本文中的“盡快返回”是指把原來復雜的條件判斷等語句用盡快返回的方式簡化代碼。

正文:如首先聲明的是前面講的“分解復雜判斷”,簡單的來說,當你的代碼中有很深的嵌套條件時,花括號就會在代碼中形成一個長長的箭頭。我們經常在不同的代碼中看到這種情況,并且這種情況也會擾亂代碼的可讀性。下代碼所示,HasAccess方法里面包含一些嵌套條件,如果再加一些條件或者增加復雜度,那么代碼就很可能出現幾個問題:1,可讀性差 2,很容易出現異常 3,性能較差

using System.Collections.Generic; using System.Linq; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; using Customer = LosTechies.DaysOfRefactoring.BreakResponsibilities.After.Customer; namespace LosTechies.DaysOfRefactoring.SampleCode.ReturnASAP.Before {public class Order{public Customer Customer { get; private set; }public decimal CalculateOrder(Customer customer, IEnumerable<Product> products, decimal discounts){Customer = customer;decimal orderTotal = 0m;if (products.Count() > 0){orderTotal = products.Sum(p => p.Price);if (discounts > 0){orderTotal -= discounts;}}return orderTotal;}} } 那么重構上面的代碼也很簡單,如果有可能的話,盡量將條件判斷從方法中移除,我們讓代碼在做處理任務之前先檢查條件,如果條件不滿足就盡快返回,不繼續執行。 下面是重構后的代碼: using System.Collections.Generic; using System.Linq; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; using Customer = LosTechies.DaysOfRefactoring.BreakResponsibilities.After.Customer; namespace LosTechies.DaysOfRefactoring.SampleCode.ReturnASAP.After {public class Order{public Customer Customer { get; private set; }public decimal CalculateOrder(Customer customer, IEnumerable<Product> products, decimal discounts){if (products.Count() == 0)return 0;Customer = customer;decimal orderTotal = products.Sum(p => p.Price);if (discounts == 0)return orderTotal;orderTotal -= discounts;return orderTotal;}} }

總結: 總結:這個重構很重要,它和前面講的“分解復雜判斷”有些類似,我們在做復雜的處理過程時,要經常考慮這個重構,用好了它,會對我們的幫助很大。

31. 使用多態代替條件判斷

概念:本文中的“使用多態代替條件判斷”是指如果你需要檢查對象的類型或者根據類型執行一些操作時,一種很好的辦法就是將算法封裝到類中,并利用多態性進行抽象調用。

正文:本文展示了面向對象編程的基礎之一“多態性”, 有時你需要檢查對象的類型或者根據類型執行一些操作時,一種很好的辦法就是將算法封裝到類中,并利用多態性進行抽象調用。

如下代碼所示,OrderProcessor 類的ProcessOrder方法根據Customer的類型分別執行一些操作,正如上面所講的那樣,我們最好將OrderProcessor 類中這些算法(數據或操作)封裝在特定的Customer 子類中。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; namespace LosTechies.DaysOfRefactoring.SampleCode.ReplaceWithPolymorphism.Before {public abstract class Customer{}public class Employee : Customer{}public class NonEmployee : Customer{}public class OrderProcessor{public decimal ProcessOrder(Customer customer, IEnumerable<Product> products){// do some processing of orderdecimal orderTotal = products.Sum(p => p.Price);Type customerType = customer.GetType();if (customerType == typeof(Employee)){orderTotal -= orderTotal * 0.15m;}else if (customerType == typeof(NonEmployee)){orderTotal -= orderTotal * 0.05m;}return orderTotal;}} } 重構后的代碼如下,每個Customer 子類都封裝自己的算法,然后OrderProcessor 類的ProcessOrder方法的邏輯也變得簡單并且清晰了。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using LosTechies.DaysOfRefactoring.SampleCode.BreakMethod.After; namespace LosTechies.DaysOfRefactoring.SampleCode.ReplaceWithPolymorphism.After {public abstract class Customer{public abstract decimal DiscountPercentage { get; }}public class Employee : Customer{public override decimal DiscountPercentage{get { return 0.15m; }}}public class NonEmployee : Customer{public override decimal DiscountPercentage{get { return 0.05m; }}}public class OrderProcessor{public decimal ProcessOrder(Customer customer, IEnumerable<Product> products){// do some processing of orderdecimal orderTotal = products.Sum(p => p.Price);orderTotal -= orderTotal * customer.DiscountPercentage;return orderTotal;}} }

總結: “使用多態代替條件判斷”這個重構在很多時候會出現設計模式中(常見的工廠家族、策略模式等都可以看到它的影子),因為運用它可以省去很多的條件判斷,同時也能簡化代碼、規范類和對象之間的職責。

代碼及PDF下載

代碼下載地址:http://github.com/schambers/days-of-refactoring

中文版PDF下載地址: 猛擊下載

轉載于:https://blog.51cto.com/knightswarrior/1261956

總結

以上是生活随笔為你收集整理的31天重构学习笔记下载的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

久草久草在线 | 国产精品99久久久久久武松影视 | 超碰在线天天 | av高清一区二区三区 | 日韩成人在线免费观看 | 国产视频导航 | 欧美日韩中文在线 | 久久99久久99精品免视看婷婷 | 91在线国产观看 | 欧美性极品xxxx娇小 | 国产无遮挡又黄又爽在线观看 | 人人舔人人爽 | 久久不卡av | www.色国产| 久久激情视频 久久 | 欧美与欧洲交xxxx免费观看 | 9幺看片 | 亚洲精品一区二区三区在线观看 | 欧美性大战久久久久 | 日韩精品免费在线 | 久久av观看| 日韩在线小视频 | 日韩精品免费一区二区 | 亚洲精品欧美精品 | 国内精品久久久久影院男同志 | 婷婷亚洲五月 | 欧美a影视 | 国产亚洲视频系列 | wwwwwww色| 久久99操| 黄色www在线观看 | 久久久91精品国产一区二区精品 | 99热亚洲精品 | 伊人视频 | 高清久久久 | 亚洲电影成人 | 成 人 黄 色 片 在线播放 | 亚洲午夜精品在线观看 | 免费a v在线| 国产打女人屁股调教97 | 日本一区二区三区免费观看 | 欧美日韩在线视频一区 | 福利视频| 国产成人精品电影久久久 | 亚洲精品自在在线观看 | 成人午夜电影在线 | 久久久久久国产精品999 | 99视频免费观看 | 精品国产aⅴ麻豆 | 色久综合 | 久久久免费观看视频 | 日韩欧美视频一区二区三区 | 亚洲天堂网视频 | 中文有码在线视频 | www.com久久 | 亚洲欧美激情插 | 久久综合色综合88 | 免费在线观看日韩视频 | 亚洲精品欧美成人 | 中文字幕在线观看资源 | 国产亚洲婷婷 | 国产群p视频 | 亚洲人成网站精品片在线观看 | 亚洲人xxx | 91精品国产一区二区三区 | 精品一区二区三区久久久 | 免费黄色在线网站 | 国产一级片在线播放 | 欧美日韩在线观看一区 | 中文字幕亚洲字幕 | 91激情| 96精品高清视频在线观看软件特色 | av中文在线影视 | 91av手机在线 | 中文字幕日韩免费视频 | 久久久久久麻豆 | 美女视频永久黄网站免费观看国产 | 91精品国产综合久久婷婷香蕉 | 日韩在线免费观看视频 | 人成午夜视频 | 一区二区三区免费在线 | 永久免费视频国产 | 激情视频一区二区三区 | 久久精品99国产 | 久久乐九色婷婷综合色狠狠182 | 狠狠干天天 | 一级特黄aaa大片在线观看 | 久久伊人国产精品 | av观看在线观看 | 国产日韩精品欧美 | 成人一级影视 | 综合久久综合久久 | 亚洲国产中文字幕在线观看 | 69亚洲精品| 国产精品女同一区二区三区久久夜 | 精品在线视频观看 | 精品一区二区三区香蕉蜜桃 | 天天操天操 | 午夜精品一二区 | 奇人奇案qvod | 九七人人干 | 美女视频又黄又免费 | 久久久久久久久久久久影院 | 国产精品午夜免费福利视频 | 99精品国产aⅴ | 久久歪歪 | 久久久亚洲国产精品麻豆综合天堂 | 婷婷激情影院 | 成年人在线看片 | 在线免费观看羞羞视频 | 精品伊人久久久 | 日本中文在线 | 国产成人99久久亚洲综合精品 | 亚洲成年人在线播放 | 国产午夜亚洲精品 | www国产亚洲精品久久麻豆 | 日韩在线不卡av | 超级碰碰碰视频 | 欧美激情第八页 | 97夜夜澡人人双人人人喊 | 日日爽| www.精选视频.com | 国产原创中文在线 | 99久久99久久精品国产片果冰 | 国产精品久久久久久久久久ktv | 999国产在线 | 久久精品网站免费观看 | 亚洲日韩中文字幕在线播放 | 视频91| 日韩中文字幕免费看 | 人人插人人爱 | 国产精品免费看久久久8精臀av | 日本在线精品视频 | 国产精品1024 | 久久久久久久国产精品 | 在线观看深夜视频 | 日韩成人欧美 | 久久高清精品 | 国产精品一区二区三区免费看 | 狠狠网站 | 国产亚洲精品福利 | 日日夜夜精品视频天天综合网 | 国产亚洲综合在线 | 国产精品一区欧美 | 亚洲国产日韩一区 | 欧美日韩啪啪 | 久久99热国产 | 久久只精品99品免费久23小说 | 国产美女免费看 | 亚洲美女在线一区 | 日韩av一卡二卡三卡 | 激情综合网五月婷婷 | 国产精品乱码高清在线看 | 国产精品第十页 | 91精品一区二区三区久久久久久 | 午夜精品福利影院 | 亚洲免费在线观看视频 | 亚洲 欧美 精品 | 亚洲黄在线观看 | 日韩精品第1页 | 综合网欧美 | 顶级欧美色妇4khd | 黄色小说18| 国产精品毛片完整版 | 岛国大片免费视频 | 2021国产视频| 瑞典xxxx性hd极品 | 91一区啪爱嗯打偷拍欧美 | 婷婷激情网站 | 欧美日韩高清一区二区 | 伊人网站 | 成人国产精品免费 | 日本激情视频中文字幕 | 四虎永久精品在线 | 精品视频免费看 | 成+人+色综合 | 九九视频在线观看视频6 | 丰满少妇在线观看 | 天天操天天操天天操天天 | v片在线看 | 精品一区二区av | 天天做天天爱天天爽综合网 | www.狠狠操.com | 国产精品麻豆欧美日韩ww | 欧美日韩性视频在线 | 中文字幕乱在线伦视频中文字幕乱码在线 | 亚洲欧美怡红院 | 欧美一区二区在线免费看 | 免费看片网址 | 久久精品中文字幕少妇 | 久久人人干 | 人人插人人看 | 亚洲精品综合一二三区在线观看 | 在线黄av | 999国产精品视频 | 国产一级片久久 | 日本公乱妇视频 | 精品一区二区在线看 | 免费观看性生交 | 中文字幕久久网 | 成人91av| 国产午夜av | 黄色亚洲免费 | 五月婷婷综合在线视频 | 亚洲久草网 | 国产精品自拍av | 国产中文字幕网 | 91av小视频 | 欧美精品久久久久久久久久久 | japanesefreesex中国少妇 | 亚洲最新合集 | 久久露脸国产精品 | 午夜黄网 | 精品视频国产 | 国产夫妻性生活自拍 | 久草视频在线播放 | 欧美精品一级视频 | 国产亚洲高清视频 | 麻豆91网站 | 99色视频 | 黄色午夜| 91免费日韩 | 人人舔人人| 日韩高清一区二区 | 激情久久久久 | 久久夜夜爽 | 亚洲v精品 | 色综合国产 | se视频网址| 九月婷婷人人澡人人添人人爽 | 在线精品观看 | 国产精品美女久久久久久 | 国产成人三级在线播放 | 六月丁香久久 | 欧美成人免费在线 | 中文字幕国产一区 | 99久久99精品 | 久久综合99| 亚洲精品在线电影 | 日本黄色免费看 | 久久久久北条麻妃免费看 | 日韩欧美69 | 激情五月av | 涩涩网站在线看 | 成人小视频在线观看免费 | 国产精品av在线免费观看 | 四虎精品成人免费网站 | 国产黄色片一级三级 | 8x成人免费视频 | 日本精品中文字幕 | 日韩91av | 黄色三级免费观看 | 中文字幕免费高清在线 | 91麻豆高清视频 | 久久 亚洲视频 | 免费在线观看黄色网 | 91xav| 国产精品一区在线播放 | 91高清不卡 | 超碰在线94| 日韩aⅴ视频 | 91亚洲精品国产 | 99久久99久久免费精品蜜臀 | 麻豆视频免费在线观看 | 欧美日在线观看 | 在线观看网站黄 | 激情影院在线观看 | 色播六月天 | 99久久精品久久久久久清纯 | 黄免费在线观看 | 国产精品video爽爽爽爽 | 亚洲成人av电影在线 | 五月婷婷色丁香 | 这里有精品在线视频 | 国产韩国精品一区二区三区 | 少妇视频一区 | 国产黄在线 | 成人国产精品久久久久久亚洲 | 黄污在线观看 | 天天躁日日躁狠狠 | 久久免费黄色网址 | 三上悠亚一区二区在线观看 | 91精品视频播放 | 91av视屏| 一区二区三区在线免费观看 | 日韩网站在线观看 | 色婷婷狠狠操 | 久精品视频在线观看 | 在线电影 一区 | 国产999精品久久久久久绿帽 | 色综合天天综合在线视频 | 国产破处在线视频 | 日本性高潮视频 | 狠日日| 久久久毛片 | 国产91精品久久久久久 | 伊人五月天.com | 91c网站色版视频 | 亚洲最大免费成人网 | 国产一级免费在线观看 | 成人久久 | 免费久久网站 | 中文字幕观看av | 欧美日韩一区二区三区在线免费观看 | 成人一级电影在线观看 | 国产亚洲精品成人av久久ww | 久久久在线视频 | 激情久久婷婷 | 久久九精品 | 亚洲视频久久久久 | 中文字幕精品一区久久久久 | 00av视频 | 国产不卡av在线播放 | 久艹在线免费观看 | 国产第一页在线观看 | 最新av免费 | 久久久久免费视频 | 日日夜夜综合 | 国产不卡视频在线播放 | 91在线看视频| av天天澡天天爽天天av | 欧美精品一区二区免费 | 激情在线网站 | 色综合天天狠天天透天天伊人 | 国产精品地址 | 国产精品欧美激情在线观看 | 国产精品自产拍 | 五月婷婷色丁香 | 国产免费视频一区二区裸体 | 日韩专区一区二区 | 精品国产成人在线影院 | 国产丝袜制服在线 | 中文字幕在线看视频国产 | 在线观看黄网 | 懂色av懂色av粉嫩av分享吧 | 日日爽天天 | 国产精品久久久久久电影 | 国产精品久久久久久久久免费 | 开心色停停 | 国产在线免费观看 | 日韩有色 | 国产精品岛国久久久久久久久红粉 | 999色视频 | 亚洲国产片色 | 一级α片免费看 | 国产精品va在线观看入 | 99热在线精品观看 | 免费观看久久久 | 国产精品国产三级国产不产一地 | 久久精品99国产国产 | 免费看国产黄色 | 在线观看黄污 | 欧美三级高清 | 国产精品理论在线观看 | 日本中文字幕电影在线免费观看 | 麻豆 videos | 日韩区欠美精品av视频 | 中国一级片视频 | 亚洲三级在线 | 99热在线观看 | 中文字幕第一页在线播放 | 欧美日本在线观看视频 | 精品国产区 | 热久在线 | 国产精品一区二区三区视频免费 | 免费在线观看91 | 在线99 | 爱色婷婷 | 国产精品1区2区3区 久久免费视频7 | 人人干在线观看 | 国产在线p| 国产精品一区二区免费视频 | 日韩在线视频观看 | 国产精品美女视频 | 中日韩免费视频 | 中文字幕国产 | 福利一区在线视频 | 97超碰资源站 | 成人免费看电影 | 日韩黄色在线观看 | 精品国产精品一区二区夜夜嗨 | 看片网站黄色 | 狠日日 | 精品夜夜嗨av一区二区三区 | 久久色视频 | 欧美精品乱码久久久久久按摩 | 成人综合免费 | 亚洲区视频在线观看 | 久久夜色网 | 成人在线观看资源 | 欧美激情第十页 | 免费91在线| 亚洲欧美日韩不卡 | 在线看一区二区 | 91精品国产综合久久久久久久 | 国产精品欧美久久 | 日本黄色黄网站 | 欧美极品一区二区三区 | 日日天天 | 日韩久久久久久久久久久久 | 国产五码一区 | 狠狠干电影 | 五月婷在线播放 | 97**国产露脸精品国产 | 久久黄色网页 | 日韩精品一区二区三区在线播放 | 精品在线亚洲视频 | 日韩有码第一页 | 日韩av线观看 | 九草在线视频 | 亚洲视频1区2区 | 国产精品mv在线观看 | 国产精品资源网 | 91福利视频久久久久 | 国产一区二区三区久久久 | 久久午夜国产 | 在线观看视频国产一区 | 丝袜精品视频 | 久久久99精品免费观看乱色 | 久久久久久久久久久黄色 | 久久av网| 婷婷在线视频观看 | 免费高清在线视频一区· | 97精品伊人 | 亚洲精品一区二区三区在线观看 | 成片人卡1卡2卡3手机免费看 | 婷婷在线不卡 | 成人三级网址 | 亚洲欧美日韩在线一区二区 | 亚洲综合视频在线 | 色狠狠综合天天综合综合 | 久久99久久精品 | 亚洲欧美少妇 | 91传媒91久久久 | 99久久久成人国产精品 | 国产在线日韩 | 一区二区在线不卡 | 婷婷久久婷婷 | 国产资源在线免费观看 | 国产精品久久久久久久午夜片 | 最新av观看 | 香蕉91视频 | 九9热这里真品2 | 五月婷婷电影网 | 国产精品破处视频 | 国产一区二区三区四区大秀 | 久久久久 免费视频 | 中文字幕在线观看视频免费 | 色欧美成人精品a∨在线观看 | 黄色av播放| 在线 高清 中文字幕 | 日韩精品久久久免费观看夜色 | 久久久久亚洲精品男人的天堂 | 欧美日韩精品在线观看视频 | 国产精品一码二码三码在线 | 中文字幕在线看人 | 91传媒在线播放 | 一区二区成人国产精品 | 色播五月激情综合网 | 97免费公开视频 | 国产亚洲精品久久久久久移动网络 | 国产亚洲精品久久久久久久久久久久 | www国产亚洲 | 免费在线观看一区 | 四月婷婷在线观看 | 97精品国产| 色综合咪咪久久网 | 奇米7777狠狠狠琪琪视频 | 91精品国产综合久久福利不卡 | 国产午夜精品一区二区三区在线观看 | av电影免费| 久久精品久久综合 | 中文字幕免费成人 | 日韩网页| 亚洲欧洲一区二区在线观看 | 91精品一区二区在线观看 | 天天爽夜夜操 | 久久久久夜色 | 又黄又爽又色无遮挡免费 | 久久人人爽爽人人爽人人片av | 天堂va在线高清一区 | 亚洲视频一区二区三区在线观看 | 天天干天天干天天射 | 男女全黄一级一级高潮免费看 | 天天射夜夜爽 | 高清国产在线一区 | 999久久久欧美日韩黑人 | 在线电影日韩 | 国产精品一区二区久久 | 亚洲精品免费视频 | 日韩av不卡在线 | 91视频在线免费观看 | a视频在线观看免费 | 免费韩国av| 亚洲精品自拍视频在线观看 | 亚洲综合五月 | 精品国产一区二区三区男人吃奶 | 日韩最新在线 | 狠狠操夜夜 | 青春草免费在线视频 | 美国人与动物xxxx | 欧美日韩免费在线视频 | 中文字幕一区二区三区乱码不卡 | 色爱区综合激月婷婷 | 人人搞人人爽 | 欧美日韩一区二区三区在线免费观看 | 麻豆视频大全 | 欧美专区日韩专区 | 亚洲精品国产区 | av中文字幕剧情 | 超碰人人草 | 天堂av在线网站 | 亚洲永久精品视频 | 成人av高清在线 | 人人插人人搞 | 国产在线观看一区 | 天天操天天干天天玩 | av在线播放网址 | 午夜私人影院 | 综合色影院 | 久久精品—区二区三区 | 日韩精品一卡 | 少妇bbw撒尿 | 成人国产电影在线观看 | 国产字幕在线看 | 国产999在线观看 | 成人在线黄色电影 | 国产丝袜在线 | 午夜精品av在线 | 国产91欧美 | 美女在线免费观看视频 | 色综合色综合久久综合频道88 | 最新国产精品久久精品 | 精一区二区| 国产91精品一区二区麻豆网站 | av官网| 中文字幕你懂的 | 欧美日韩18| 久久在现视频 | 不卡电影一区二区三区 | 国产日韩精品在线观看 | 在线视频一区二区 | 久久久久久久久久久网站 | 久久午夜电影院 | 在线亚洲欧美日韩 | 91精品国产高清自在线观看 | 久久精品国产精品亚洲精品 | 伊人网av| 最近高清中文字幕在线国语5 | 欧美精品中文字幕亚洲专区 | 日本丶国产丶欧美色综合 | 日韩网站在线免费观看 | 精品久久五月天 | 色综合天天色综合 | 香蕉影视在线观看 | 欧美福利网站 | 91九色最新地址 | 黄在线免费观看 | 久久综合九色综合欧美就去吻 | 国产成人av | 美女网站在线观看 | 中文字幕精品www乱入免费视频 | 成年人视频在线观看免费 | 成人av电影免费观看 | 超碰官网 | 日韩成人看片 | 日韩一区精品 | 国产色婷婷在线 | 一区久久久 | 女人魂免费观看 | av中文字幕第一页 | 久久综合久久综合这里只有精品 | 99久久99视频只有精品 | 欧美日韩aaaa| 99精品视频在线看 | 国产精品系列在线观看 | 国产aa精品| 亚洲综合日韩在线 | 久久久污 | 国产精品永久 | 91香蕉久久 | 夜夜爽88888免费视频4848 | 免费视频一区 | 91av视频在线观看免费 | 日本二区三区在线 | 精品资源在线 | 午夜久久久精品 | 日韩在线播放av | 91看片黄色 | 成年人黄色大片在线 | 欧美激情视频一二区 | 中文字幕亚洲综合久久五月天色无吗'' | 久久精品99国产精品亚洲最刺激 | 日韩美视频 | 欧美久久久久久久久久久久 | 免费激情网 | 91香蕉亚洲精品 | 精品亚洲va在线va天堂资源站 | 蜜臀久久99精品久久久无需会员 | 中文字幕在线不卡国产视频 | 911免费视频 | 中文区中文字幕免费看 | 中文字幕 第二区 | 欧美日韩国产一区二区三区在线观看 | av在线精品 | 亚洲精品乱码久久久久久高潮 | 日本婷婷色 | 国产色网站 | 黄色精品在线看 | 一区二区亚洲精品 | 久久精品国产第一区二区三区 | 成人夜晚看av| 99爱精品视频 | 久久精品这里热有精品 | 欧美亚洲三级 | 国产一区自拍视频 | 国产剧情一区二区在线观看 | 色婷婷99| 免费观看一级视频 | 亚洲爱爱视频 | 99久久久久| 久久久久9999亚洲精品 | 国产成人av一区二区三区在线观看 | 九精品 | 最近久乱中文字幕 | 高清精品视频 | 国模视频一区二区三区 | 色婷婷精品 | 超碰99人人 | 亚洲精品国产精品国自产在线 | 久久精品波多野结衣 | 91av在线免费观看 | 五月天婷婷丁香花 | 日日干av | 美女福利视频网 | 91在线看免费 | 亚洲a资源 | 最近中文字幕视频完整版 | 麻豆传媒视频观看 | a级一a一级在线观看 | 国产一级片直播 | 九色精品免费永久在线 | 天天做天天爱天天综合网 | 国产高清视频在线免费观看 | www.色婷婷.com| 极品美女被弄高潮视频网站 | www.久久色 | 久久黄色影视 | 日韩免费高清在线观看 | 久草在线资源视频 | 噜噜色官网 | 麻豆av一区二区三区在线观看 | 国产精品久久久久影院 | 日韩av一区二区在线播放 | .国产精品成人自产拍在线观看6 | 日韩高清不卡在线 | 日韩欧美一区二区在线播放 | 久久精品日产第一区二区三区乱码 | 99综合影院在线 | 91av亚洲| 国产理论片在线观看 | 国产男女无遮挡猛进猛出在线观看 | 国产99久久久国产精品免费二区 | 日产乱码一二三区别免费 | 91视频在线国产 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产一区国产二区在线观看 | 久久视频二区 | 日韩网站在线播放 | 日本久久久久久 | 激情电影影院 | 国产一级视频免费看 | av片子在线观看 | 中文字幕亚洲高清 | 午夜精品一二区 | 成人欧美一区二区三区在线观看 | 精品国内 | 国产美女视频免费 | 欧洲一区二区在线观看 | 在线视频 国产 日韩 | 中文字幕在线观看不卡 | 97香蕉久久超级碰碰高清版 | 九九热在线精品 | 欧美日韩在线观看不卡 | 91在线porny国产在线看 | 四虎8848免费高清在线观看 | 99在线观看免费视频精品观看 | 色偷偷男人的天堂av | 色亚洲网 | 国产精品毛片久久久久久久久久99999999 | 天天干天天插伊人网 | 高清免费在线视频 | 国产精品视频你懂的 | 欧美日韩国产一区二区三区 | 四虎成人网 | 亚洲资源视频 | 99精品影视 | 一区二区三区免费在线观看 | 免费在线观看av网站 | 久久影视中文字幕 | 在线观看日本高清mv视频 | 亚洲免费小视频 | 亚洲激情综合网 | 久久免费在线 | 国产1区2区 | 国产美女视频免费观看的网站 | 69久久夜色精品国产69 | 日韩精品一区二区三区水蜜桃 | 天天爽网站| 亚洲日本黄色 | 亚洲精品99久久久久久 | 视频成人免费 | 成人免费在线播放 | 亚洲精品国精品久久99热 | 日本系列中文字幕 | 五月婷婷激情六月 | 18+视频网站链接 | 九九九热精品 | 天天干天天干天天操 | 极品美女被弄高潮视频网站 | 一区二区中文字幕在线 | 国产一区二三区好的 | 欧美性大战久久久久 | 在线天堂视频 | 午夜的福利| 夜夜夜草 | av在线一级 | 久久er99热精品一区二区三区 | 激情伊人五月天 | 在线天堂8√| 97精产国品一二三产区在线 | 中文字幕制服丝袜av久久 | 日韩精品中文字幕在线不卡尤物 | 草久久久久久 | 五月婷婷六月丁香在线观看 | 国内精品视频在线播放 | 高清av不卡| 久久久久麻豆v国产 | 国产色视频 | 日产中文字幕 | 国产精品av电影 | www.天天操 | 久久久久久久av麻豆果冻 | 日韩精品一区二区三区外面 | 五月综合色婷婷 | 欧美日韩激情视频8区 | 亚洲视频分类 | 天天操夜夜爱 | 日韩欧美xx| 中文字幕丝袜一区二区 | 国产精品18久久久久久久久久久久 | 9999在线观看| 国产日韩在线视频 | 黄av免费 | 久久视频网 | 欧美精品久久人人躁人人爽 | 麻豆av一区二区三区在线观看 | 成人久久免费 | 天天操夜夜做 | 激情欧美日韩一区二区 | 亚洲精品玖玖玖av在线看 | 亚洲精品免费看 | 日韩在线播放欧美字幕 | 免费av电影网站 | av电影一区 | 成人亚洲欧美 | 一区二区三区在线看 | 最近中文字幕免费观看 | 亚洲视频 视频在线 | 中日韩欧美精彩视频 | 成人精品视频久久久久 | 国产黄在线观看 | 在线观看aaa | 久久成人免费视频 | 欧美日韩网站 | 久久久免费电影 | 欧美日韩视频精品 | 亚洲91精品 | 亚洲欧美国产视频 | 久久久国际精品 | 成人av影视在线 | 日本黄色免费网站 | 久久免费一 | 国产黄色在线看 | 久久这里只有精品9 | 久久er99热精品一区二区三区 | 久草com| 久久久久人人 | 国产精品aⅴ| 国产亚洲综合性久久久影院 | 亚洲精品视频免费观看 | 欧美日韩午夜爽爽 | 91精品一区二区三区久久久久久 | 午夜精品久久久久久久久久久久 | 久久久麻豆精品一区二区 | 99色精品视频 | 国产视频一区在线 | 成人a级大片 | 麻豆国产视频 | 日韩精品欧美视频 | avsex| 午夜精品一区二区三区视频免费看 | 在线日本v二区不卡 | 性色av一区二区三区在线观看 | 国产精品美女久久久久久免费 | 黄色中文字幕在线 | 美女一级毛片视频 | 婷婷五综合 | 欧美激情综合五月色丁香 | 亚洲美女精品 | 欧美日韩高清一区二区三区 | 天天爽天天爽天天爽 | 高清免费在线视频 | 久久精品国产免费看久久精品 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 国产精品女同一区二区三区久久夜 | 欧美日韩在线电影 | 日日摸日日添日日躁av | 国产视频2| 99人久久精品视频最新地址 | 国产精品av电影 | 国产精品原创av片国产免费 | 午夜精品影院 | 一区 二区电影免费在线观看 | 久久99精品国产91久久来源 | 久久久久久久久久久免费 | 亚洲影院天堂 | 色爱区综合激月婷婷 | 久一久久 | 国产精品久久久久久久久久免费 | 国产色婷婷在线 | 青青草国产在线 | av线上看 | 日韩无在线 | 日韩精品久久久久久久电影竹菊 | 亚洲欧洲中文日韩久久av乱码 | 91在线www| 中文字幕亚洲在线观看 | 91中文字幕在线观看 | 国产精品久久久久久一区二区 | 人人添人人澡人人澡人人人爽 | 国产精彩视频 | 日韩网站在线看片你懂的 | 91在线九色 | 亚洲精品成人免费 | 缴情综合网五月天 | 久草视频在线资源 | 久久国产精品免费看 | 免费av网站观看 | 日韩在线精品视频 | 亚洲 欧洲 国产 日本 综合 | 免费福利片 | 国产精品欧美激情在线观看 | 国产精品九色 | 欧美日本中文字幕 | 亚洲国产精品日韩 | 婷婷网在线 | 婷婷日日 | 久久精品欧美一 | 美女视频久久久 | 精品视频久久 | 99在线热播| 色综合天天视频在线观看 | 综合国产在线观看 | 中文字幕日韩有码 | 国产69精品久久久久久久久久 | 欧美一级视频一区 | 亚洲免费国产视频 | 亚洲日本va午夜在线电影 | 久久99免费视频 | 国产精品久久av | 精品在线观看免费 | 日韩一区精品 | 久久久久久美女 | 日韩有码在线播放 | 天天干,天天射,天天操,天天摸 | 日韩免费看 | 天天曰视频 | 国产精品一区二区在线播放 | 色香蕉在线 | 五月精品 | 久久久久一区二区三区 | 黄色网大全 | 亚洲精品国产精品国自产观看 | 一区二区网 | 亚洲精品高清在线 | 久久成人免费电影 | 91在线亚洲| 国产成人免费网站 | 欧美日韩一区二区久久 | 亚洲精品视频在线观看网站 | 日韩欧美在线中文字幕 | 91爱爱电影 | 四虎在线免费观看 | 午夜久久美女 | 国产精品影音先锋 | 99久久精品国产观看 | 亚洲aⅴ在线观看 | 欧美精品亚洲精品 | 精产嫩模国品一二三区 | 久久精品999 | 久久精品在线免费观看 | 国产精品国产亚洲精品看不卡15 | 婷婷六月久久 | 人人插超碰 | 亚洲精品免费观看视频 | 超碰人人干人人 | 亚洲精品国产精品国产 | 日韩欧美国产免费播放 | 久久久久久美女 | 98涩涩国产露脸精品国产网 | 日本mv大片欧洲mv大片 | 亚洲性少妇性猛交wwww乱大交 | 亚洲国产小视频在线观看 | 日本一区二区三区视频在线播放 | 在线免费观看羞羞视频 | 久久免费在线观看 | 97精品一区二区三区 | 免费在线播放av电影 | 国产自产在线视频 | 国产99久久久国产精品免费二区 | 国精产品999国精产品视频 | 欧美日韩视频网站 | 天天操天天操 | 欧美日韩中文字幕视频 | 精品99久久 | 亚洲视频免费视频 | 97碰碰视频 | japanesexxx乱女另类 | 久久久久日本精品一区二区三区 | 亚洲永久av | 精品亚洲va在线va天堂资源站 | 一区二区三区不卡在线 | 亚洲午夜精品久久久 | 一区中文字幕 | 三三级黄色片之日韩 | 91av在线播放视频 | 国产片免费在线观看视频 | 久久免费视频播放 | 亚洲毛片视频 | 午夜婷婷在线播放 | 99久久久久久久久久 | 日韩激情片在线观看 | 91九色蝌蚪视频网站 | 片网站| av高清免费在线 | 国际精品久久久久 | 成人免费视频免费观看 | 日韩精品在线视频免费观看 | 精品一区 在线 | 人人插人人费 | 六月丁香六月婷婷 | 日韩中文字幕在线看 | 狠狠的操狠狠的干 | 91看毛片| 国产精品女同一区二区三区久久夜 | 亚洲五月综合 | 在线视频1卡二卡三卡 | avhd高清在线谜片 | 亚洲精品永久免费视频 | www.97色.com| 国产露脸91国语对白 | 96在线 | 91色国产 | 成人免费观看在线视频 | 国产美女视频 | 中文字幕二区在线观看 | 日韩成人精品在线观看 | 一区二区三区在线电影 | 国产精久久 | 伊甸园av在线 | 国产1区在线观看 | 精品成人久久 | 亚洲成年片 | 91九色在线视频观看 | 久久亚洲婷婷 | 免费看污污视频的网站 | 国产一线天在线观看 | 中文字幕观看av | 91色影院| 在线观看第一页 | 狠狠色综合欧美激情 | 在线a人v观看视频 | 中文字幕精品一区 | 丁香激情综合久久伊人久久 | 免费视频久久 | 亚洲免费色| 国产片免费在线观看视频 | 国内综合精品午夜久久资源 | 91成人午夜 | 天天操天操 | 婷婷中文字幕综合 | 国产日韩欧美视频在线观看 | www.色午夜 | 天天天天色射综合 | 精品视频123区在线观看 | 成人久久亚洲 | 国产精品久久久久久久久久久免费看 |