精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從把三千行代碼重構成15行代碼談起

開發 后端
重構的目的,是讓你的代碼更為精簡、穩定、能夠重用,是最大程度的讓功能和業務分離。在重構的過程中,你的閱讀代碼的能力、寫出優秀代碼的能力以及系統架構能力都會穩步提升。

如果你認為這是一個標題黨,那么我真誠的懇請你耐心的把文章的第一部分讀完,然后再下結論。如果你認為能夠戳中您的G點,那么請隨手點個贊。

把三千行代碼重構為15行

那年我剛畢業,進了現在這個公司。公司是搞數據中心環境監控的,里面充斥著嵌入式、精密空調、總線、RFID的概念,我一個都不懂。還好,公司之前用Delphi寫的老客戶端因為太慢,然后就搞了個Webform的替代,恰好我對Asp.Net還算了解,我對業務的不了解并不妨礙我稱成為這個公司的一個程序員。小公司也有小公司的好,人少,進去很快負責代碼開發。我當然也就搞這個數據中心智能管理系統啦。

這個系統非常的龐大,尤其牛逼的是支持客戶端組態,然后動態生成網頁,數據還能通過Socket實時監控(那時我還真就不懂網絡編程)。這個對于當時的我來說,真真是高、大、上吶!!當時跟著了解整個系統大半個月才算能夠調試,寫一些簡單的頁面。

在維護系統的過程中,時不時要擴展一些功能,也就接觸了下面這個類:

看到沒有,就是當年最最流行的三層架構的產物,對于剛出茅廬的毛頭小子來說,這是多么專業的文件頭注釋,還有反射也就算了,這構造函數還能靜態的,還能私有的?那時剛接觸這么高大上的代碼的我,瞬間給跪了!

但是,類寫多了,我就感覺越來越別扭,就是下面這段代碼:

每增加一個表,除了要改接口、要改DAL、要改BLL之外,還得在這個工廠類添加一個方法,真真是累到手抽筋,即使有當時公司了的G工給我推薦的神器——動軟代碼生成器,這粘貼復制的幾遍,也是讓我感覺到異常繁瑣,有時候打鍵盤稍微累了點,還把復制出來代碼改錯了,你妹的,難道這就是程序員該干的事情,不,絕對不是!我想起了一句至理名言:當你覺得代碼重復出現在程序中的時候,就應該重構了。是的,在這句話的指導下,我開始了折騰,決定挑戰這個高大上的代碼,事實證明,思想的力量是無窮的。

那么,怎么修改呢,仔細觀察之后,發現其中className的生成跟返回的類型非常類似,只是一個是類名,一個是字符串,這兩者之間應該能夠關聯起來。于是google了一下(當時GFW還沒猖獗起來哈),隱隱約約就找到了“反射”這兩個字,深入了解之后,確定可以完成。

接下來,就是返回的類型了,返回的類型并不固定,但是似乎很有規律……這個似乎好像在哪里見過,對了,模板,C++課程上有講過的,于是再次google,了解到了C#中使用了泛型代替了C++中的模板。在學習完泛型和反射之后,并參考了網上的一些文章,我搗鼓出了下面的代碼:

沒錯,就是它了,三層架構年代最流行的工廠類……

看著原來滾十幾屏幕的代碼,變成了十多行的代碼,真是爽到了骨子里去了,太干凈了!唯一讓我擔憂的是,我進公司的時候,幫忙整理公司申請軟件著作權都是需要代碼量的,根據代碼多少行來評估軟件的大小,萬一老板知道了我非但沒有幫公司增加代碼量,還減少了,會不會立即把我開掉?我沒敢給我們老板展示我優秀的成果,所幸,這段代碼非但沒有出過任何問題,還避免了以前同事老是在新增一個類之后,把代碼復制過來,但是沒有正確修改的問題,大大提高了效率。雖然,我沒敢大事宣布我的勞動成果,但是這次成功的修改,則徹底讓我走上了代碼重構的不歸路。

看到這里,大家應該知道這個案例是否真實的了吧。我相信,從08年開始的碼農們,看到這種類似的代碼絕對不比我少。那么,我想告訴你們的是什么呢?

  •  要在編程過程中多思考
  •  編程的思想很重要,請多看點經典的書
  •  從小處著眼,慢慢重構,尤其在應對一個大型的系統
  •  當重復出現的時候,你應該考慮重構了
  •  粘貼復制的代碼越少,你的系統越穩定

少用代碼生成器

我們來分析一下,為什么我之前的前輩會寫出上面的代碼。我歸結起來有以下幾點:

  •  因為使用了動軟代碼生成器,生成代碼方便,就沒多想了。
  •  三層架構的概念倒是了解了,但是沒有去深入思考就拿來應用
  •  遇到重復的代碼,沒有重構的概念,這是思想的問題——思想比你的能力重要

至今為止,還是很多人使用代碼生成器,那么我們應該怎么對待這個問題呢。我認為,代碼生成器確實可以減少你不少工作,但是少用,那些重復性的工作,除了部分確實是沒有辦法的,其他大部分都是可以通過框架解決的,舉例來說,像三層架構,真正需要用到代碼生成器的,也就是Model類而已,其他的完全可以在框架中完成。因此你要竭盡全力的思考怎么在框架中來減少你的重復性工作,而不是依賴于代碼生成器。

另外,如果你還是在用相關的代碼生成工具,請重新定義“動軟代碼生成器”的代碼模板,自己寫一個模板;或者使用CodeSmith來完全制定自己的代碼生成,因為動軟給的代碼模板真心亂,比如下面這段代碼: 

  1. for (int n = 0; n < rowsCount; n++)  
  2.  
  3.     model = new DBAccess.Model.eventweek();  
  4.     if(dt.Rows[n]["GroupNo"].ToString()!="")  
  5.     {  
  6.         model.GroupNo=int.Parse(dt.Rows[n]["GroupNo"].ToString());  
  7.     }  
  8.     if(dt.Rows[n]["Week0"].ToString()!="")  
  9.     {  
  10.         model.Week0=int.Parse(dt.Rows[n]["Week0"].ToString());  
  11.     }  
  12.     if(dt.Rows[n]["Week1"].ToString()!="")  
  13.     {  
  14.         model.Week1=int.Parse(dt.Rows[n]["Week1"].ToString());  
  15.     }  

首先,你就不能用 var row=dt.Rows[n] 替代嗎?其次,直接用int.Parse如果拋出了異常性能得有多低?再次,這段代碼要是有點修改,我不是要每個dt.Rows[n]得改一遍?

不要重復發明輪子

我們再來看看其他的一些代碼: 

  1. public List<string> GetDevices(string dev){  
  2.     List<string> devs=new List<string>();  
  3.     int start=0 
  4.     for(int i=0;i<dev.Length;i++){  
  5.         if(dev[i]=='^'){  
  6.             devs.Add(dev.SubString(start,i));  
  7.             start=i+1;  
  8.         }  
  9.     }  
  10.     return devs;  

有沒有很眼熟,沒錯,這就是對String.Split()函數的簡單實現。我的前輩應該是從c++程序員轉過來的,習慣了各種功能自己實現一遍,但是他忽略了C#的很多東西。我們不去評判這段代碼的優劣,而實際上他在很長一段時間都運行得很好。我們來看看使用這一段代碼有什么不好的地方:

  •  重復發明輪子。花費了額外的時間,函數的健壯性和很差
  •  可讀性差。其實是一個很簡單的功能,但是用上了這么一段函數,起初我還以為有什么特別的功能。

那么,我們應該怎樣去避免重復發明輪子呢?我從個人的經歷來提出以下幾點,希望能夠對各位有所幫助:

  •  了解你所學的編程語言的特性。你可以看一本基礎的入門書籍,把所有的特性瀏覽一遍,或者上MSDN,把相關的內容過一遍。
  •  在你決定動手發明一個輪子之前,先搜索一下現成的解決方案。你還可以到CodeProject、GitHub之類的網站搜索一下。在知乎上有很多人都在批評這么一種現象,老是問一些重復性的問題,然后又職責知乎沒落了,沒有人回答他的問題,實際上相關問題已經有了很詳細的解答,那提問之前,不能首先去搜一下是否有現成的答案,反而指責沒有回答他的問題呢?
  •  你有一定的基礎之后,還應該去讀一下相關的經典書籍,深入了解其中的原理。比如,你覺得你有一定的基礎了,我建議你去把《CLR Via C#》多讀幾遍,你了解原理越多,你越是能夠利用這編程語言的特性,從而來實現原本那些你認為要靠自己寫代碼的功能。

這里我再舉一個我自己的例子。在我現有的程序中,我發現我需要越來越多的線程來執行一些簡單的任務,比如在每天檢測一下硬盤是否達到90%了,每天9點要控制一下空調的開啟而在網上6點的時候把空調關掉。線程使用越來越多,我越是覺得浪費,因為這些現場僅僅只需完成一次或者有限的幾次,大部分時間都是沒有意義的,那么怎么辦呢?我決定自己寫一個任務類,來完成相關的事情。說干就干,我很快把這個類寫出來了。 

  1. public abstract class MissionBase : IMission  
  2.  
  3.     private DateTime _nextExecuteTime;  
  4.     protected virtual DateTime[] ExecuteTimePoints { get; private set; }  
  5.     protected virtual int IntervalSeconds { get; private set; }  
  6.     protected IEngine Engine { get; private set; }  
  7.     public bool IsCanceled{get{……}}  
  8.     public bool IsExecuting{get{……}}  
  9.     public bool IsTimeToExecute{get{……}}  
  10.     public abstract bool Enable { get; }  
  11.     public abstract string Name { get; }  
  12.     protected MissionBase(IEngine engine)  
  13.     {  
  14.         ExecuteTimePoints = null;//默認采用間隔的方式  
  15.         IntervalSeconds = 60 * 60;//默認的間隔為1個小時  
  16.         Engine = engine 
  17.     }  
  18.     /// 任務的執行方法  
  19.     public void Done()  
  20.     { 
  21.          if (Interlocked.CompareExchange(ref _isExecuting, 1, 0) == 1) return;  
  22.         try  
  23.         {  
  24.             ……  
  25.         }  
  26.         finally  
  27.         {  
  28.             Interlocked.CompareExchange(ref _isExecuting, 0, 1);  
  29.         }  
  30.     }   
  31.     ///實際方法的執行  
  32.     protected abstract void DoneReal();  

但是,實際上這個任務方法,并不好用,要寫的代碼不少,而且可靠性還沒有保障。當然,我可以繼續完善這個類,但是我決定搜索一下是否還有其他的方法。直到有一天,我再次閱讀《CLR Via C#》,看到線程這一章,講到了System.Threading.Timer以及ThreadPool類時,我就知道了,使用Timer類完全可以解決我的這個用盡量少的線程完成定時任務的問題。

因為從原理上來說,Timer類無論你聲明了多少個,其實就只有一個線程在執行。當你到了執行時間時,這個管理線程會用ThreadPool來執行Timer中的函數,因為使用的ThreadPool,執行完成之后,線程就馬上回收了,這個其實就完全實現了我所需要的功能。

等你無法重構的時候再考慮重寫

我帶過很多優秀的程序員,也與很多優秀的程序員共事過。有一大部分的程序員在看到一套系統不是那么滿意,或者存在某些明顯的問題,就總是忍不住要把整套系統按自己覺得可以優化的方向來重寫,結果,重寫結構往往并不令人滿意。系統中確實存在很多不合理的地方,但是有不少的這種代碼,恰恰是為了解決一些特定場景下的問題的。也就是說,所有的規范以及編程的原則,其實也是有條件限制的,他可能在大部分的時候是正確的,能夠指導你完成你的任務,但是,并不是在所有地方都是適用的。比如數據庫范式,但實際中我們的設計往往會考慮冗余,這是違背范式的,但是為什么還有那么多人趨之若鶩呢?因為我們可能需要用空間換時間。

如果我們一開始就考慮重寫,那么你可能會陷入以下的困境:

  •  需要花更大的精力來完成一些看似簡單的BUG

    你要知道,有一部分看似錯誤或者非常不優美的代碼,其實恰恰是為了解決一些非常刁鉆的問題的。

  •  再也無法兼容老的系統了

    你急于把原有系統重寫,卻往往忽略了對原有系統的兼容,那么你新的系統的推進則會十分緩慢。而老系統的維護,又會陷入及其尷尬的情況。

  •  過度設計,導致重寫計劃遲遲無法完成

    有重寫沖動的程序員往往是在架構設計上有一些讀到的見解,他們善于利用所學的各種設計模式和架構技巧來建立系統,但是越是想盡可能的利用設計模式,越是陷入過度設計的困局,導致重寫的計劃遲遲都無法完成。

  •  無法有效利用現有系統已經完成并測試的代碼

    如果你確實有必要進行重寫,我還是建議你把代碼盡可能的重構。因為重構之后的系統,能夠讓你更輕易的重寫,又最大限度了保留以前可用的業務代碼。

我舉個例子,說明如何通過重構更好的利用現有代碼的。

我有一個非常龐大的系統,其中有一塊功能是用于數據采集、存儲、告警管理以及電話、短信等告警通知。大致的結構如下: 

  1. class MainEngine:IEngine{  
  2.     public MainEngine(ConfigSettings config){    
  3.     }  
  4.     public void Start(); 
  5.      public void Stop();  

需要增加新的業務功能時,程序員寫的代碼往往是這樣的:首先時修改配置類 

  1. class ConfigSettings{  
  2.     public bool NewFuncEnable{get;private set;}  
  3.     public ConfigSettings(){ 
  4.          NewFuncEnable=xx;//從配置文件讀取  
  5.     }  

接著修改主程序: 

  1. class MainEngine:IEngine{  
  2.     private NewFuncClass newnewCls=new NewFuncClass();  
  3.     public MainEngine(ConfigSettings config){  
  4.     }  
  5.     public void Start(){  
  6.         if(config.NewFuncEnable)  
  7.             newCls.Start();  
  8.     }  
  9.     public void Stop(){  
  10.         if(config.NewFuncEnable)  
  11.             newCls.Stop();  
  12.     }  

在修改的過程中,往往是根據配置文件來判斷新功能是否啟用。上面代碼會造成什么問題呢:

  • 主程序代碼和擴展功能耦合性太強,每增加一個功能都要修改主程序代碼,這里非常非常容易出錯。尤其是新的人進度開發組,很容易就忘主程序中增加了一些致命性的代碼。比如上述的擴展功能,可能是在特定的項目中才會有這個擴展功能,但是,寫代碼的人忘記增加是否啟用的配置選項了,導致所有的項目都應用了這個功能,而這個功能需要特定的表,這樣就悲劇了。即使是你增加了配置,也是非常的不美觀,因為在通用的版本中使用了這個配置,往往會讓定制項目以外的人員感到困惑。
  •  增加擴展功能的人還需對整個MainEngine代碼有一定的熟悉,否則,他根本就不知道在Start方法和Stop方法進行newClas的對應方法的調用
  •  如果你打算對這段代碼進行重寫,那么,你會感到非常的困難,因為你分不清楚newCls這個新實例的作用,要么你花大精力去把所有代碼理清楚,要么直接就把這段新增的業務代碼去掉了。

那么我們如何對這段代碼進行重構呢。首先,我們把新功能注冊的代碼抽取出來,通過反射來實現新的功能的注冊。 

  1. private void RegisterTaskHandlerBundles()  
  2.  {  
  3.      var bundles = xxx.BLL.Caches.ServiceBundleCache.Instance.GetBundles("TaskHandlerBundle");  
  4.      if (bundles != null && bundles.Count > 0)  
  5.      {  
  6.          var asmCache = new Dictionary<string, Assembly>();  
  7.          foreach (var bundle in bundles)  
  8.          {  
  9.              try  
  10.              {  
  11.                  if (!asmCache.ContainsKey(bundle.Category)) asmCache.Add(bundle.Category, Assembly.Load(bundle.AssemblyName));  
  12.                  var handler = (ITaskHandler)asmCache[bundle.Category].CreateInstance(bundle.ClassName, false, BindingFlags.Default, null,  
  13.                      new object[] { this, bundle }, null, null);  
  14.                  _taskHandlerBundles.Add(bundle, handler); 
  15.               }  
  16.              catch (Exception e)  
  17.              {  
  18.                  NLogHelper.Instance.Error("加載bundle[Name:{0},Assembly:{1}:Class:{2}]異常:{3}", bundle.Name, bundle.AssemblyName, bundle.ClassName, e.Message);  
  19.              }  
  20.          }  
  21.      }  
  22.  } 

修改MainEngine代碼 

  1. class MainEngine:IEngine{  
  2.     private NewFuncClass newnewCls=new NewFuncClass();  
  3.     public MainEngine(ConfigSettings config){  
  4.         RegisterTaskHandlerBundles();  
  5.     }  
  6.     public void Start(){  
  7.         _taskHandlerBundles.Start();  
  8.     }  
  9.     public void Stop(){  
  10.         _taskHandlerBundles.Stop();  
  11.     } 

OK,現在我們再來看看怎么實現原來的新增功能:你只需按規范新建一個類,繼承ITaskHandler接口,并實現接口的方法。最后在XTGL_ServiceBundle表中新增一條記錄即可。我們再來看看這么做有什么好處:

  •  新增的類只需按規范寫即可,完全對MainEngine代碼沒有任何影響。你甚至可以把這個MainEngine代碼寫在一個新建的Dll中。
  •  新增功能的這個業務類跟原來的代碼解耦,非常方便進行新功能的業務測試,而無需考慮原有框架的影響
  •  新增功能的業務類與架構完全分離,我們在重寫代碼中只要保證接口的穩定性,無論我們怎么把系統架構重寫,我們可以馬上就重用上原有的業務功能代碼。

重構的目標之一,就是把框架和業務完全分離。

有志于深入了解的同學,可以了解下反射、Ioc和插件話編程等。

學會單元測試,培養你的重構意識

可能上面說了這么多,還是有很多人并不理解重構。沒關系,在這里我教你們一個快速入門的辦法,就是單元測試。什么是單元測試,請自行google。單元測試有什么要求?就是要求你要把每個方法都弄成盡量可以測試的。盡量讓你的方法變成是可測試的,就是培養你重構意識的利器。在你要求把方法變成可測試的過程,你就會發現你必須得不斷的修改你的方法,讓它的職責盡量單一,讓它盡量的與上下文無關,讓它盡可能通過方法參數的輸入輸出就能完成相關的功能,讓依賴的類都盡量改為接口而不是實例。最終,你就會發覺,這就是重構!而且是在不知不覺中,你重構的功力就會大大提升,你編程的水平也會大大提升!

看到這里,有經驗的程序員就會問,你這是在鼓勵我使用TDD嗎?不,不是的。TDD(Test-Driven Development)鼓勵的是測試驅動開發,未開發之前先編寫單元測試用例代碼,測試代碼確定需要編寫什么產品代碼。這是一種比較先進的開發方法,但是在編程的實踐過程中,我認為它過于繁瑣,很多中小企業很難實施,更別提我們個人開發者。我這里提倡你用單元測試培養你的重構意識,可以說是一種后驅動,用于提高你的重構能力和重構愿望,你完全可以把我的這個方法稱為“TDR(Test-Driven Refactoring)——測試驅動重構”。當然,在開發之前如果你有意識的讓方法可測試,那么你寫出來的函數將會是比較高質量的代碼。當你的函數都是一個個可重用性高的函數之時,你將會發現,寫代碼其實就像堆積木一樣,可以把一個大型的需求分解成無數細小的功能,很快的把需求實現。

以下是一個超大方法中的一段代碼,如果你懂得怎樣讓這段代碼編程一個可測試的方法,那么,恭喜你,你入門了。

所謂重構

如果你有耐心看到這里,你應該知道,我并非一個標題黨,而這篇文章也許稱為“如何在編程中應用重構的思想”更為貼切,但是我不想用這么嚴肅的標題。

很多編程初學者,或者有多年編程經驗的人都覺得閱讀別人的代碼非常困難,重構更是無從談起,他們要么對這些代碼望洋興嘆,要么就是推翻從來。但是,如果我們有重構的意識,以及在編程的過程中熟悉一些代碼調整和優化的小技巧,你自然而然就會培養出重構的能力。

重構,其實很簡單:

  •  把基礎打牢固
  •  多看點優秀的代碼
  •  避免復制粘貼,如果看見重復代碼時應該有意識要消滅它
  •  減少對代碼生成器的依賴
  •  在處理現有代碼時盡量用重構代替重寫,在重寫之前一定要先重構
  •  盡量讓所有的方法都是可測試的

如果你堅持這么去做了,一段時間之后感覺自然就出來了。

重構的目的,是讓你的代碼更為精簡、穩定、能夠重用,是最大程度的讓功能和業務分離。在重構的過程中,你的閱讀代碼的能力、寫出優秀代碼的能力以及系統架構能力都會穩步提升。你成為一個優秀的程序員將指日可待。

 

 

責任編輯:龐桂玉 來源: 碼道成功
相關推薦

2014-12-01 11:15:40

2015-08-17 10:42:13

2018-10-15 09:20:08

代碼軟件工程師

2025-02-24 08:20:00

AI代碼生成

2022-07-13 17:56:09

Bug率產品經理系數

2025-09-10 08:23:11

代碼重構技巧

2016-12-02 08:53:18

Python一行代碼

2019-03-04 15:53:02

SQL存儲系統

2020-01-10 22:56:56

Python圖像處理Linux

2022-10-28 10:18:53

代碼績效Java

2024-04-09 15:22:24

2019-02-18 16:21:47

華為代碼重構

2021-06-28 16:05:19

數據庫代碼技術

2021-06-30 13:45:49

SQL數據庫LSM

2020-04-01 12:18:11

人工智能強化學習開源

2018-05-13 15:24:33

工程師程序windows

2019-10-20 20:22:05

Python 開發編程語言

2023-09-12 10:10:57

開發者工具開源

2019-11-12 13:06:20

代碼開發工具

2017-04-10 09:59:08

python代碼愛心線
點贊
收藏

51CTO技術棧公眾號

成人久久久久| 亚洲涩涩在线| 国产精品一区二区久久精品爱涩| 免费av一区二区| 国产成人精品无码片区在线| 在线亚洲人成| 国产精品久久久久婷婷二区次| 91麻豆国产精品| 日本一区二区三区免费视频| 国产欧美高清视频在线| 日韩午夜在线观看视频| 国产三区在线视频| h网站久久久| 26uuu久久天堂性欧美| 国产一区在线播放| 天天操天天摸天天干| 天天综合亚洲| 亚洲美女性生活视频| 一二三av在线| 香蕉成人av| 亚洲一区二区欧美| 亚洲在线不卡| 狠狠狠综合7777久夜色撩人| 国v精品久久久网| 国产精品一二区| 日本aⅴ在线观看| 欧美日韩在线观看视频小说| 精品国产91久久久久久久妲己| 成人性生交免费看| 伊人久久国产| 午夜在线电影亚洲一区| 国产又大又长又粗又黄| 青青草免费观看免费视频在线| 国产一区二区在线看| 国产精品99久久久久久久久 | 国产亚洲精品aa| 成人h在线播放| 91禁在线观看| 免费欧美日韩国产三级电影| 欧美性受xxxx白人性爽| 久久久久亚洲AV| 亚洲va在线| 日韩中文字幕av| 男人舔女人下部高潮全视频| 久久精品色播| 精品国产1区2区3区| 中文字幕亚洲日本| 蜜桃精品视频| 欧美一级黄色录像| 肉色超薄丝袜脚交| 精品久久免费| 欧美一级艳片视频免费观看| 特级西西444www| 天堂久久一区| 欧美电影在线免费观看| 中文字幕第38页| 亚洲一区有码| 正在播放一区二区| 亚洲精品mv在线观看| 亚州精品国产| 欧美一卡二卡在线观看| 日本在线观看视频一区| 午夜视频一区二区在线观看| 欧美一区二区三区免费| 污免费在线观看| 日韩视频在线直播| 亚洲аv电影天堂网| 久久久久久久人妻无码中文字幕爆| 日韩免费成人| 亚洲国产精品专区久久| 欧美性xxxx图片| 免费看日本一区二区| 国产小视频国产精品| www亚洲色图| 久久视频精品| 久热爱精品视频线路一| 国产精品变态另类虐交| 亚洲一区二区伦理| 国产精品福利网| 国产精品久久久久久久久久久久久久久久久久 | 亚洲第一综合网站| xxxx另类黑人| 日韩欧美亚洲一二三区| 怡红院亚洲色图| 日韩av综合| 亚洲激情自拍图| 国产123在线| 欧美精品偷拍| 欧美做爰性生交视频| 中文字幕一级片| 国产成人在线观看| 久久国产精品一区二区三区四区| 极品白浆推特女神在线观看 | 麻豆精品蜜桃| 欧美一区二区三区在| 少妇一级淫片免费放播放| 狠狠操综合网| 麻豆一区二区在线观看| 天天操天天摸天天干| 久久成人综合网| 国产精品一区二区三区免费观看| 国产资源在线看| 亚洲乱码日产精品bd| 久久久噜噜噜www成人网| 亚洲色图图片| 亚洲美女激情视频| 青青草免费av| 秋霞影院一区二区| 国产区一区二区| 91精彩视频在线播放| 亚洲不卡在线观看| www.污污视频| 国产精品羞羞答答在线观看| 九九视频这里只有精品| 国产精品欧美综合| 成人动漫av在线| 在线精品亚洲一区二区| 成人片免费看| 精品乱码亚洲一区二区不卡| 免费黄色国产视频| 男人的天堂成人在线| 999在线观看免费大全电视剧| 精品三级久久久久久久电影聊斋| 亚洲综合成人网| 亚洲一区二区福利视频| 国产免费播放一区二区| 91高清视频免费观看| 国产成人精品亚洲精品色欲| 国产精品三级av| 欧美视频第三页| 狼人精品一区二区三区在线| 久久中国妇女中文字幕| 中文字幕+乱码+中文乱码91| 91丨porny丨在线| 成人网站免费观看入口| 日韩免费成人| 久久综合电影一区| 91久久精品无码一区二区| 久久精品欧美日韩精品| 毛片在线视频播放| 国产精品中文字幕制服诱惑| 欧美激情一区二区三区成人| 国产免费不卡视频| 亚洲图片激情小说| 911av视频| 99久久激情| 91精品久久久久久久久不口人| 国产福利在线视频| 在线欧美日韩国产| 精品无码在线观看| 日韩av高清在线观看| 欧美一区1区三区3区公司 | 欧美性jizz18性欧美| yy6080午夜| 91久久中文| 久久av一区二区三区亚洲| 玖玖在线播放| 日韩av最新在线| 香蕉影院在线观看| 国产亚洲欧美在线| 国产裸体免费无遮挡| 欧美精选一区二区三区| 国产精品久久色| 久热国产在线| 日韩一级免费观看| 青青草原在线免费观看视频| 成人高清在线视频| 日韩在线一级片| 精品不卡一区| 成人妇女淫片aaaa视频| sm国产在线调教视频| 精品国产一区二区三区忘忧草 | 开心激情五月网| 韩国成人在线视频| 国产黄色激情视频| 日韩三级av| 国产精品久久久久久久久久免费 | 丰满熟女一区二区三区| 五月综合激情日本mⅴ| 午夜理伦三级做爰电影| 美女视频黄a大片欧美| 中国女人做爰视频| 亚洲成a人片77777在线播放| 国产精品第一页在线| 中文在线观看免费| 日韩黄在线观看| 亚洲怡红院av| 亚洲成人在线观看视频| 这里只有久久精品| 国产经典欧美精品| 男人和女人啪啪网站| 婷婷亚洲五月色综合| 国产精品一区二区欧美黑人喷潮水| 久久久久久久| 美女av一区二区| 青青草av免费在线观看| 91精品国产高清一区二区三区| 国产精品久久久久久久久久久久久久久久久| 国产性色一区二区| 免费看91视频| 人人超碰91尤物精品国产| 国产又粗又猛又爽又黄的网站| 妖精视频一区二区三区免费观看| 51成人做爰www免费看网站| 欧美aa一级| 久久色免费在线视频| 日本护士...精品国| 日韩一区二区精品葵司在线| 潘金莲一级淫片aaaaaa播放| 一区二区三区四区蜜桃| 中字幕一区二区三区乱码| 不卡的av在线| 三级黄色片免费看| 日韩黄色小视频| 国产精品无码av在线播放| 97色伦图片97综合影院| 欧美乱偷一区二区三区在线| 日韩一区二区三区精品| 国产精品自产拍在线观看中文| zzzwww在线看片免费| 久久久电影免费观看完整版| 国产对白叫床清晰在线播放| 亚洲精品国产电影| www香蕉视频| 制服丝袜中文字幕亚洲| 在线免费观看av片| 欧美影院一区二区三区| 久久久久女人精品毛片九一| 亚洲第一在线综合网站| 伊人在线视频观看| 中文字幕在线不卡一区二区三区| 波多野结衣办公室33分钟| 国产成人av电影免费在线观看| 天天干天天av| 老色鬼精品视频在线观看播放| 无码人妻丰满熟妇区五十路百度| 亚洲毛片视频| 国产日韩av网站| 在线成人欧美| 欧美乱大交xxxxx潮喷l头像| 欧美1区3d| 国产人妻互换一区二区| 国产精品久久久久一区二区三区厕所 | 国产区精品在线| 5858s免费视频成人| 一级特黄aaa| 欧美老人xxxx18| 国产精品怡红院| 欧美一区二区视频网站| 国产黄色一级大片| 日韩欧美视频在线| 亚洲第一天堂网| 精品国产一区二区精华| 六月婷婷综合网| 亚洲精品电影在线| 欧洲视频在线免费观看| 亚洲欧美色图片| sese在线视频| 菠萝蜜影院一区二区免费| 二区三区在线观看| 欧美激情中文字幕在线| 日韩深夜视频| 国产精品高潮呻吟久久av无限 | 欧美日韩国产综合一区二区| 一区二区三区免费在线| 91精品国产aⅴ一区二区| 亚洲国产精品二区| 日韩av影视在线| 黄色av免费在线观看| 日韩中文字在线| 欧美卡一卡二| 午夜精品国产精品大乳美女| free欧美| 91影视免费在线观看| 精品视频在线你懂得| 欧美一区二区三区精美影视| 日韩在线欧美| h无码动漫在线观看| 嫩草成人www欧美| 人人爽人人爽av| www.欧美日韩| 国产18无套直看片| 一个色在线综合| 久久久蜜桃一区二区| 538prom精品视频线放| 亚洲av成人无码网天堂| 日韩中文字幕免费| av最新在线| 国产欧美一区二区| 韩国女主播一区二区三区| 四虎一区二区| 亚洲高清资源| 在线免费视频一区| av午夜一区麻豆| 色偷偷www8888| 日韩欧美aaa| 一区二区国产欧美| 亚洲第一精品福利| 日韩伦理在线观看| 5252色成人免费视频| 国产日本亚洲| 日本精品一区| 99精品国产99久久久久久福利| 亚洲性图一区二区| 久久女同互慰一区二区三区| 青青草免费av| 欧美日韩性生活| 欧洲视频在线免费观看| 久久99久久99精品免观看粉嫩| 亚洲精品555| 蜜桃av久久久亚洲精品| 欧美另类女人| 久久久免费视频网站| 粉嫩在线一区二区三区视频| 91无套直看片红桃在线观看| 日韩人在线观看| 欧美 日韩 国产 成人 在线 91| 久久精品2019中文字幕| 写真福利精品福利在线观看| 国产伦精品一区二区三区四区视频| 手机在线电影一区| 91人人澡人人爽人人精品| 成人免费福利片| 欧美日韩精品在线观看视频 | 精品一区二区三| 成人一对一视频| 国产91综合一区在线观看| www.av免费| 欧美巨大另类极品videosbest | 日韩一区日韩二区| 中文字幕+乱码+中文乱码www| 亚洲人成在线观| 一二三四视频在线中文| 国内一区二区三区在线视频| 欧美日韩福利| 国产又粗又猛又爽又黄| 亚洲三级久久久| 99久久久久成人国产免费| 久久精品成人动漫| 91九色成人| 国产精品夜夜夜爽张柏芝| 麻豆国产一区二区| 国产精品国产三级国产传播| 欧美日韩国产首页| 日本不卡不卡| 91亚洲精品久久久| 国产精品vip| 这里只有精品在线观看视频 | 缅甸午夜性猛交xxxx| 成人精品国产福利| 国产午夜激情视频| 亚洲精品电影在线| 北岛玲heyzo一区二区| 欧美人与性禽动交精品| 日韩精彩视频在线观看| 99久久精品久久亚洲精品| 欧美日韩国产欧美日美国产精品| 免费在线视频欧美| 51国偷自产一区二区三区的来源| 欧美精品偷拍| 免费中文字幕av| 色婷婷激情综合| 91露出在线| 亚洲自拍偷拍视频| 在线精品一区| 精品人伦一区二区三电影| 欧美日韩一级二级| 自拍亚洲图区| 久久精品中文字幕一区二区三区 | 国产v综合ⅴ日韩v欧美大片| 日韩国产综合| 久久aaaa片一区二区| 午夜视频久久久久久| 看电影就来5566av视频在线播放| 国产日韩视频在线观看| 欧美精品午夜| 午夜理伦三级做爰电影| 777a∨成人精品桃花网| 国产无遮挡裸体视频在线观看| 欧美午夜免费| 国产麻豆精品theporn| 永久免费看片在线播放| 中文字幕亚洲无线码在线一区| 91九色鹿精品国产综合久久香蕉| 日韩在线一级片| 亚洲欧美日韩小说| 亚洲aaa在线观看| 91久久在线观看| 久久成人一区| 麻豆成人在线视频| 亚洲人成网站777色婷婷| 国产高清精品二区| 午夜肉伦伦影院| 亚洲精品国产第一综合99久久 | 国产女人水真多18毛片18精品视频| 国产精品自偷自拍| 日本成熟性欧美| 午夜激情一区| 久操视频在线观看免费| 亚洲精品电影在线观看|