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

如何組織 Go 代碼?Go 作者的回答驚呆了

開發 后端
我花了很多時間在生產應用程序的兩個寵物項目中嘗試不同的方法。在本文中,我將向你展示所有選擇并告訴你它們的優缺點。閱讀完這篇博文后,你將不會有一種“統治所有模式的模式”。

[[432784]]

這是最常見的問題之一。你可以通過互聯網尋找這個問題的答案。不過,我不確認我的設計是否 100% 正確,但希望給你一些參考。

前段時間,我有幸見到了 Robert Griesemer[1](Go 的作者之一)。我們問了他這個問題:“如何組織 Go 代碼?”。他說:“我不知道。” - 這很顯然并不令人滿意,我知道。當我們問他如何設計他的代碼時,Robert 說他總是從扁平結構開始,并在必要時創建包。

我花了很多時間在生產應用程序的兩個寵物項目中嘗試不同的方法。在本文中,我將向你展示所有選擇并告訴你它們的優缺點。閱讀完這篇博文后,你將不會有一種“統治所有模式的模式”。

01 在我們開始之前

無論你如何組織代碼,你都必須考慮閱讀它的人。最重要的是你不應該讓你的貢獻者或同事思考。把所有東西都放在明顯的地方。不要重新發明輪子。你還記得 Rob Pike[2] 說過的關于 go fmt 的話嗎?

Gofmt 的風格沒有人喜歡,但 gofmt 是每個人的最愛。

你可能不喜歡眾所周知的模式。堅持下去對我們和整個社區都更好。但是,如果你有充分的理由做出不同的決定,那也沒關系。如果你的包設計良好,源代碼樹會很好地反應出來。

讓我們從文檔開始。每個開源 Go 項目在 pkg.go.dev[3] 上都有它的文檔。對于每個包,你首先看到的是包的概述。以net/http包為例,在描述每個公共函數、常量或類型之前,你需要對包提供的內容進行描述。你可以從中學習如何使用 API 和更深入的細節。從哪個來源生成概覽?該net/http包有一個 doc.go[4] 文件,作者在其中放置了該包的一般描述。你可以將此概述放在文件夾中的任何其他文件中,但 doc.go 大家公認的標準。

那么Readme文件中應該有什么?首先,對這個項目的總體概述——它的目標。然后,你應該有一個快速入門部分,你可以在其中描述開始處理項目時應該做的事情,包括任何依賴項,如 Docker 或我們正在使用的任何其他工具。你可以在此處找到基本示例或指向更詳細描述項目的外部網站的鏈接。你必須記住,此處應保留的內容取決于項目。你必須從讀者的角度思考。什么信息對他們最重要?

當你有更多文檔要提供時,將它們放入docs文件夾中。不要將它們隱藏在像/common/docs 中。這種方法有好處:很容易找到,并且在一個拉取請求中,你可以更改公共 API 及其文檔。你不必克隆另一個存儲庫并在它們之間同步更改。

我的下一個建議可能讓你吃驚。我建議使用眾所周知的工具,例如make,我知道有一些替代品,例如 sake[5], mage[6]、zim[7]或 opctl[8]。問題是要開始使用它們,你必須學習它們。如果任何項目都使用不同的自動化工具,新維護人員將更難開始。我的觀點是你應該明智地選擇你的工具。你使用的工具越多,項目啟動工作就越困難,特別有新人加入。

我一直在從事一個項目,我必須在本地運行 2 個不同的依賴項,在 CLI 中登錄到 AWS 帳戶,并連接到虛擬網絡才能在我的 PC 上運行測試。基本設置需要一兩天才能完成,我想我不必告訴你這些測試有多么不穩定[9]。

關于 linting 建議使用 golangci-lint[10]。啟用對你的項目來說似乎合理的所有 linter。通常使用默認啟用的 linter 規則可能是一個好的開始。

02 扁平結構(單包)

讓我們從最推薦的方法開始:只要你不被迫添加新包,就將整個代碼保存在根文件夾中。在項目開始時,這種方式真的挺好。當我開始使用它時,我發現它很有幫助,并且對它最終將如何工作有一個模糊的想法。

將所有內容放在一個地方有助于避免包之間的循環依賴。當你將某些內容放入單獨的包時,你會發現需要根文件夾中的其他內容,你將被迫為此共享依賴項創建第三個包。隨著項目的發展,情況變得更糟。你最終可能會擁有許多包,其中大多數包幾乎都依賴于其他包。許多函數或類型必須是公開的。這種情況模糊了 API,使其更難閱讀、理解和使用。

使用單個包,你不必在文件夾之間跳來跳去并思考架構,因為所有的內容都在一個地方。這并不意味著你必須將所有內容都保存在一個文件中,例如:

  1. courses/ 
  2.   main.go 
  3.   server.go 
  4.   user_profile.go 
  5.   lesson.go 
  6.   course.go 

在上面的例子中,每個邏輯部分都被組織成單獨的文件。當你犯了錯誤并將結構放入錯誤的文件時,你所要做的就是將其剪切并粘貼到新位置。你可以這樣考慮:單個文件代表應用程序的一個實體部分。你可以按代碼(HTTP 處理程序、數據庫存儲庫)或其提供的內容(管理用戶的配置文件)對代碼進行分組。當你需要某樣東西時,你就會知道在哪里可以找到它。

什么時候創建一個新包?如果你有充分的理由這樣做,比如:

1)當你有不止一種啟動應用程序的方式時

假設你有一個項目,并且希望以兩種模式運行它:CLI 命令和 Web API。在這種情況下,創建一個/cmd包并包含 cli和web子包是很常見的。

  1. courses/ 
  2.   cmd/ 
  3.     cli/ 
  4.       main.go 
  5.       config.go 
  6.     web/ 
  7.       main.go 
  8.       server.go 
  9.       config.go 
  10.   user_profile.go 
  11.   lesson.go 
  12.   course.go 

你可以將多個main()函數放入單個文件夾中的單獨文件中。要運行它們,你必須提供一個明確的文件列表來編譯,而其中只有一個要 main()。這使應用程序的運行變得非常復雜。更簡單的方式是直接輸入 go run ./cmd/cli。

當你有一個子包時,./cmd/ 文件夾的使用可能聽起來過于復雜。我發現它在需要添加時很有用,例如,使用來自消息代理的消息。此主題將在拆分依賴項的部分中更詳細地介紹。

2)當你想提取更詳細的實現時

標準庫就是一個很好的例子。讓我們看看 net/http/pprof[11] 包。該net包為網絡 I/O 提供了一個可移植的接口,包括 TCP/IP、UDP、域名解析和 Unix 域套接字。你可以根據此包提供的內容構建你想要的任何協議。net/http 包使我們能夠發送或接收 HTTP 請求。HTTP 協議使用 TCP/UDP,因此http包是 net 的子包是很自然的。net/http/pprof包中的所有類型和方法都可以返回 HTTP 協議,因此自然是一個 http 子包。

database/sql包也是如此。如果你有更多非關系數據庫的實現,它們將放在database包下,和 sql包同級。

你看出來模式了嗎?數據包(packet )在樹中(tree)越深,傳遞的細節就越多。換句話說,每個子包都在父包上提供了更具體的實現。

3)當你開始為密切相關的事物添加公共前綴時

一段時間后,你可能會注意到,為了避免誤解或命名沖突,你開始為函數或類型添加前綴或后綴。通過這樣做,我們試圖模擬項目中缺少包的情況可能是一個好兆頭。很難說什么時候提取新的子包。每次當你看到它提高了 API 的可讀性并使代碼更清晰時請提取新的子包。

  1. r := networkReader{} 
  2.  
  3. // 
  4.  
  5. r := network.Reader{} 

如你所見,扁平結構既簡單又強大。在某些用例中,你可能會發現它很有用且很有幫助。這種組織代碼的方式不僅僅適用于小型或新建項目。以下是遵循單包模式的庫示例:

  • https://github.com/go-yaml/yaml
  • https://github.com/tidwall/gjson

值得記住的是,你不需要不惜一切代價堅持這種組織代碼的方式。保持簡單是有原因的,但添加更多包可能會使你的代碼更好。不幸的是,沒有銀彈。你需要做的是嘗試并詢問你的同事或維護人員哪個選擇對他們來說更具可讀性。

03 模塊化

之前描述的組織代碼的方式在某些場景可能效率不高。我花了很多時間試圖獲得“正確的”項目結構。一段時間后,我注意到對于業務應用程序,我開始嘗試另一種類似的方式組織代碼。

當我們開發直接為客戶提供客戶端的應用程序時,扁平結構可能效率不高。你希望創建提供一組與控制器、基礎設施或業務領域的一部分相關的功能的模塊。讓我們仔細看看兩種最流行的方法,并談談它們的優缺點。

按種類(kind)組織

這個模型很受歡迎。我認識的人沒有提倡使用這種策略來組織代碼的,但我在新舊項目中都發現了它。按種類組織是一種策略,它試圖通過將部分放入基于其結構的桶中,從而為過于復雜的代碼單元帶來秩序。將包稱為repositories 或 model 是很常見的。這樣做的結果是你會創建類似 utils 或者 helpers 的包,因為你覺得應該把一個函數或一個結構放在一個單獨的地方,但沒有找到任何合適的地方。

  1. ├── handlers 
  2. │   ├── course.go 
  3. │   ├── lecture.go 
  4. │   ├── profile.go 
  5. │   └── user.go 
  6. ├── main.go 
  7. ├── models 
  8. │   ├── course.go 
  9. │   ├── lecture.go 
  10. │   └── user.go 
  11. ├── repositories 
  12. │   ├── course.go 
  13. │   ├── lecture.go 
  14. │   └── user.go 
  15. ├── services 
  16. │   ├── course.go 
  17. │   └── user.go 
  18. └── utils 
  19.     └── stings.go 

在上面的示例中,你可以看到項目是按類型組織的。你什么時候想添加新功能或修復與課程相關的錯誤,你會從哪里開始尋找?在一天結束時,你將開始從一個包跳到另一個包,希望能在那里找到有用的東西。

Graph that shows dependencies between packages

這種方法有其后果。每個類型、常量或函數都必須是公共的,才能在項目的另一部分中訪問。你最終將大多數類型標記為公有。即使對于那些不應該公開的人。它混淆了應用程序的這一部分中的重要內容。其中許多是可能隨時更改的細節。

另一方面,按種類組織對我們來說是很自然的。我們是在處理程序或數據庫表的類別中思考的技術人員。這就是我們的成長方式,也是我們被教導的方式。如果你沒有經驗,這種方法可能更有益,因為它可以幫助你更快地開始。從長遠來看,你可能會遇到不便,但這并不意味著你的項目會失敗 — 恰恰相反,有很多成功的應用程序都是以這種方式設計的。

按組件組織

組件是應用程序的一部分,它提供獨立的特性,很少或沒有外部依賴。你可以將其視為插件,當你將其中之一移除時,整個應用程序仍然可以運行,但功能有限。它可能發生在運行數月或數年的生產應用程序中。

應用程序可能具有一個或多個提供業務價值的核心組件。在領域驅動設計術語中,組件是有界上下文。我們將在以后的文章中用 Go 的上下文來描述 DDD。

包的 API 應該描述包提供的內容而不是更多。它不應該暴露任何從消費者的角度來看不重要的低級細節。它應該盡可能簡約。消費者可能是另一個包或另一個導入我們代碼的開發人員。

該組件應包含提供業務價值所需的一切。這意味著,每個存儲、HTTP 處理程序或業務模型都應該存儲在文件夾中。

  1. ├── course 
  2. │   ├── httphandler.go 
  3. │   ├── model.go 
  4. │   ├── repository.go 
  5. │   └── service.go 
  6. ├── main.go 
  7. └── profile 
  8.     ├── httphandler.go 
  9.     ├── model.go 
  10.     ├── repository.go 
  11.     └── service.go 

由于以這種方式組織代碼,當你擁有與任務相關的課程時,你就知道從哪里開始尋找。它沒有分布在整個應用程序中。然而,要實現良好的模塊化并不容易。可能需要多次迭代才能實現一個好的封裝 API。

還有一個挑戰。如果這些包相互依賴怎么辦?假設你想在用戶的個人資料上顯示最近的課程。它們應該共享相同的存儲庫或服務嗎?

在這種特殊情況下,從個人信息(profile)文件的角度來看,課程是一種外部依賴。解決該問題的最佳方法是在 profile 必須需要的方法的包中創建一個接口。

  1. type Courses interface { 
  2.   MostRecent(ctx context.Context, userID string, max int) ([]course.Model, error) 
  3. }  

在course包中,你公開了一個實現此接口的服務。

  1. type Courses struct { 
  2.   // maybe some unexported fields 
  3.  
  4. Func (c Courses) MostRecent(ctx context.Context, userID string, max int) ([]Model, error) { 
  5.   // return most recent coursers for specific user 

在main.go中你從course包中創建Courses的結構實例并將其傳遞給profile包。在profile包中的測試中,你創建了一個 mock 實現。因此,你甚至可以在沒有course實現包的情況下開發和測試 profile 功能。

如你所見,模塊化使代碼更具可維護性和可讀性,但它需要你更加努力地思考你的決策和依賴關系。該邏輯可能看起來非常適合新包,但似乎太小了。另一方面,在處理項目期間,現有包的部分可能會開始增多,并在一段時間后提升為自主代碼段。

當代碼在包內部增多時,你可能會問自己:如何組織單個模塊內部的代碼?這是另一個難以回答的問題。在本節中,我展示了使用應用程序組件時的扁平結構。但是,有時這還不夠……

04 簡潔的架構

你可能聽說過以下術語:Clean Architecture[12]、Onion Architecture 或類似術語。Uncle Bob 寫了一本書[13],詳細描述了每一層的含義以及應該或不應該包含的內容。這個想法很簡單。你的應用程序或模塊有 4 層(取決于你的代碼庫有多大):Domain、Application、Ports、Adapters。在某些來源中,名稱可能不同。例如,作者沒有使用 Ports 和 Adapters,而是使用 Inbound 和 Outbound。核心思想類似。讓我們用例子來描述每一層。

Domain

這是我們應用程序的核心。每個業務邏輯都應該在這里。這意味著如果更改或添加任何業務需求,你必須更新我們的域部分。這個包應該沒有任何外部依賴。它不應該知道這段代碼是在哪個上下文中執行的。這意味著,它不應該依賴任何基礎設施部分或知道任何 UI 細節。

  1. course := NewCourse("How to use Go with smart devices?"
  2. s := course.AddSection("Getting started"
  3. l := s.AddLecture("Installing Go"
  4. l.AddAttachement("https://attachement.com/download"
  5. // etc 

請注意,此時你并不關心課程的存儲位置或如何添加新課程(使用 HTTP 請求或使用 CLI)。在domain包中,你描述了課程可能包含的內容以及你可以對其進行的操作。就這些!

Application

該層包含應用程序的每個用例。它是基礎設施和 Domain 之間的粘合點。在這個地方,你獲得輸入(從它來自的任何地方),將其應用于域對象,然后將其保存或發送到其他地方。

  1. func (c Course) Enroll(ctx context.Context, courseID, userID string) error { 
  2.   course, err := c.courseStorage.FindCourse(ctx, courseID) 
  3.   if err != nil { 
  4.    return fmt.Errorf("cannot find the course: %w"
  5.   } 
  6.    
  7.   user, err := c.userStorage.Find(ctx, userID) 
  8.   if err != nil { 
  9.    return fmt.Errorf("cannot find the user: %w"
  10.   } 
  11.    
  12.   if err = user.EnrollCourse(course); err != nil { 
  13.    return fmt.Errorf("cannot enroll the course: %w"
  14.   } 
  15.    
  16.   if err = c.userStorage(ctx, user); err != nil { 
  17.    return fmt.Errorf("cannot save the user: %w"
  18.   } 
  19.    
  20.   return nil 
  21. }  

在上面的代碼中,你可以找到用戶注冊課程的用例。它是兩部分的組合:與域對象(User,Course)和基礎設施(存儲和獲取數據)交互。

Adapters

適配器也稱為 Outbound 或基礎設施(Infrastructure)。該層負責與外界存儲和獲取數據。它可以是數據庫、blob 存儲、文件系統或其他(微)服務。通常,該層在應用程序層的接口中具有其表示形式。它有助于在不運行數據庫或將文件寫入文件系統的情況下測試應用程序層。

適配器是對低級細節的抽象,因此你軟件的其他部分不必“知道”你使用的是哪個數據庫版本、SQL 查詢長什么樣或你存儲文件的位置。

Ports

Ports(稱為 Inbound)是應用程序的這一部分,負責從用戶那里獲取數據。它可以是 HTTP 處理程序、事件處理程序或 CLI 命令。它獲取用戶的輸入并將其傳遞給 Application 層。此操作的結果返回到 Port。

  1. func enrollCourse(w http.ResponseWriter, r *http.Request) { 
  2. body, err := io.ReadAll(r.Body) 
  3.  if err != nil { 
  4.    w.WriteHeader(http.StatusBadRequest) 
  5.    logger.Errorf("cannot read the body: %s", err) 
  6.    return 
  7.  } 
  8.   
  9.  req := enrollCourseRequest{} 
  10.  if err = json.Unmarshal(body, &req); err != nil { 
  11.    w.WriteHeader(http.StatusBadRequest) 
  12.    logger.Errorf("cannot unmarshal the request: %s", err) 
  13.    return 
  14.  } 
  15.   
  16.  if err = validate.Struct(req); err != nil { 
  17.    w.WriteHeader(http.StatusBadRequest) 
  18.    logger.Errorf("cannot validate the request: %s", err) 
  19.    return 
  20.  } 
  21.   
  22.  if err = app.EnrollCourse(req.CourseID, req.UserID); err != nil { 
  23.    w.WriteHeader(http.StatusInternalServerError) 
  24.    logger.Errorf("cannot enroll the course: %s", err) 
  25.    return 
  26.  } 

請注意,編寫執行相同邏輯的 CLI 命令很簡單。唯一的區別是輸入的來源。

  1. var userID string 
  2. var courseID string 
  3.  
  4. var enroleCourseCmd = &cobra.Command{ 
  5.  Use:   "courseID userID"
  6.  Args: cobra.MinimumNArgs(2), 
  7.  Run: func(cmd *cobra.Command, args []string) { 
  8.   if err = app.EnrollCourse(courseID, userID); err != nil { 
  9.    w.WriteHeader(http.StatusInternalServerError) 
  10.    logger.Errorf("cannot enroll the course: %s", err) 
  11.    return 
  12.   } 
  13.  }, 

保持這些層的整潔和一致可能會給你的代碼帶來很多價值。它易于測試,職責明確,從哪里開始尋找要更改的代碼更加明顯。如果是與課程相關的錯誤并且是業務邏輯問題,則你將開始檢查 Domain 或 Application 層。

另一方面,很難保持界限清晰和一致。它需要大量的自律、經驗和至少幾次迭代才能正確完成。這就是為什么很多人在這個領域失敗的原因。

05 總結

組織代碼很困難。更困難的是,應用程序的體系結構在其生命周期內可能會更改幾次,進化。你可以從扁平結構開始,但最終會得到多個模塊和許多子包。不要期望第一次就做對。它可能需要多次迭代并從其他人那里收集反饋。

此外,你可以根據應用程序的不同部分混合不同的代碼組織方式。在你的業務邏輯部分,可以從模塊化開始。但是,許多應用程序需要的實用程序就不適合用現有的包,你可以在那里遵循扁平結構模式。

原文鏈接:https://developer20.com/how-to-structure-go-code/

參考資料

[1]Robert Griesemer: https://en.wikipedia.org/wiki/Robert_Griesemer

[2]Rob Pike: https://www.youtube.com/watch?v=PAAkCSZUG1c

[3]pkg.go.dev: https://pkg.go.dev/

[4]doc.go: https://github.com/golang/go/blob/master/src/net/http/doc.go

[5]sake: http://tonyfischetti.github.io/sake/

[6]mage: https://github.com/magefile/mage

[7]zim: https://github.com/fugue/zim/

[8]opctl: https://opctl.io/

[9]不穩定: https://testing.googleblog.com/2020/12/test-flakiness-one-of-main-challenges.html

[10]golangci-lint: https://github.com/golangci/golangci-lint

[11]net/http/pprof: https://pkg.go.dev/net/http/pprof

[12]Clean Architecture: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

[13]寫了一本書: https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164

本文轉載自微信公眾號「幽鬼」,可以通過以下二維碼關注。轉載本文請聯系幽鬼公眾號。

 

責任編輯:武曉燕 來源: 幽鬼
相關推薦

2021-03-17 11:47:37

tomcatJavaServerJava

2015-05-19 14:30:48

加密視頻加密億賽通

2024-07-05 11:47:43

2013-08-09 10:37:31

代碼數據

2021-03-07 22:37:17

Go代碼模式

2021-12-13 22:52:37

iphone iOSHTML

2021-05-28 10:09:22

GC詳解Java JVM

2020-04-02 07:31:53

RPC超時服務端

2015-06-24 16:09:54

Easy Connec深信服

2021-09-11 22:32:26

Go 綁定 Host

2025-04-02 00:45:00

JupyterDrawData數據

2025-11-04 02:00:00

2023-03-07 08:00:12

netpollGo

2021-05-24 11:05:53

代碼開發Go

2021-05-20 10:00:56

Go代碼Python

2022-09-13 14:44:40

HashMap哈希表紅黑樹

2021-07-05 18:05:40

SpringBean方法

2020-10-31 09:06:37

C語言編程語言

2023-09-12 11:10:00

代碼優化Go

2022-05-13 23:46:52

GO編程內存
點贊
收藏

51CTO技術棧公眾號

国产亚洲二区| 香蕉影视欧美成人| 国产精品露脸自拍| 在线观看亚洲网站| 一区二区三区免费在线看| 亚洲午夜羞羞片| 欧美激情视频一区二区三区| 中文字幕视频一区二区| 午夜精彩国产免费不卡不顿大片| 亚洲精品一区二区精华| 波多野结衣作品集| 在线播放蜜桃麻豆| 久久久久久久久久久99999| 国产主播在线一区| 亚洲天堂一区在线观看| 午夜精品久久久久久久四虎美女版| 亚洲二区在线播放视频| 欧美午夜aaaaaa免费视频| 污视频网站在线免费| 国产午夜精品一区二区| www.成人三级视频| 国产精品免费无遮挡无码永久视频| 中文字幕免费一区二区三区| 国产亚洲精品美女久久久久| 无码人妻少妇色欲av一区二区| 欧美伦理91| 国产久卡久卡久卡久卡视频精品| 污污在线观看| 在线三级中文| 国产寡妇亲子伦一区二区| 国产精品18久久久久久麻辣| 国产乡下妇女做爰毛片| 97精品视频| 亚洲欧美日韩国产中文| 在线精品视频播放| 日韩精品一区二区av| 日韩一二三区| 欧美日韩免费不卡视频一区二区三区| 五十路熟女丰满大屁股| 成人看av片| 国产精品久久夜| 国产精品99一区二区三区| 一区在线播放| 日韩电影中文字幕一区| 精产国品一区二区三区| 欧美日韩喷水| 北条麻妃av高潮尖叫在线观看| 日本www在线观看视频| 久久久久久99精品| 在线不卡免费av| 四虎免费在线观看视频| 99青草视频在线播放视| 国产拍揄自揄精品视频麻豆| 茄子视频成人在线观看| 牛牛澡牛牛爽一区二区| 91麻豆视频网站| 久久国产精品一区二区三区四区| 成人免费公开视频| 不卡av在线网| 久久久精品动漫| 姝姝窝人体www聚色窝| 成人涩涩免费视频| 国产精品乱子乱xxxx| 亚洲国产精品18久久久久久| 国产91在线看| 国内精品国语自产拍在线观看| 亚洲精品字幕在线观看| 不卡电影免费在线播放一区| 久久精品女人的天堂av| 男人的天堂在线视频| 国产欧美一区二区精品久导航| 日韩一本精品| 国产三区在线观看| 一区二区在线免费观看| 99在线精品免费视频| 美女高潮在线观看| 色噜噜狠狠一区二区三区果冻| 男女午夜激情视频| xxxxx.日韩| 日韩三级免费观看| 亚洲自拍偷拍精品| 亚洲免费专区| www.xxxx精品| 国产无码精品在线播放| 水蜜桃久久夜色精品一区的特点| 国产精品久久久久aaaa九色| 国产麻豆免费视频| av在线不卡观看免费观看| 欧美一区1区三区3区公司| 午夜在线播放| 亚洲二区视频在线| 一本久道中文无码字幕av| 亚洲美女色播| 亚洲国产高清高潮精品美女| 欧美波霸videosex极品| 欧美日韩免费观看一区=区三区| 久久久久久久久久av| 无码人妻精品一区二区蜜桃色欲| 精品夜夜嗨av一区二区三区| 国产精品swag| 91网在线播放| 午夜精品爽啪视频| 五月天视频在线观看| 成午夜精品一区二区三区软件| 亚洲美女自拍视频| √天堂中文官网8在线| 毛片一区二区| αv一区二区三区| 丝袜熟女一区二区三区| 成人黄视频免费| 91麻豆精品91久久久久久清纯| 日韩电影免费观看在线观看| 久久久久成人精品无码中文字幕| 99精品国产99久久久久久97| 日韩和欧美一区二区三区| 91久久久久久久一区二区| 日本中文字幕一区二区有码在线| 亚洲视频在线一区| 欧美videofree性高清杂交| 日韩免费高清在线观看| 伊人久久国产精品| 99久久99久久精品免费看蜜桃| 亚洲欧美日韩精品久久久| 岛国av免费在线观看| 制服.丝袜.亚洲.另类.中文| 久久av无码精品人妻系列试探| 国内精品嫩模av私拍在线观看| 日韩电影一区二区三区| 国产成人免费网站| 亚洲一区二区三区视频播放| 国产粉嫩一区二区三区在线观看| 亚洲午夜av在线| 亚洲热在线视频| 98精品久久久久久久| 国产精品成av人在线视午夜片 | 黄色一区二区在线| 久久久福利视频| 日韩精品久久久久久久酒店| 国产一区二区精品在线观看| 亚洲视频在线观看日本a| 日韩伦理三区| 亚洲人午夜精品免费| 天天综合天天干| av一本久道久久综合久久鬼色| 欧美a级免费视频| 欧美视频三区| 欧美成人精品激情在线观看 | 欧美自拍资源在线| 亚洲色图官网| 亚洲欧美在线免费| 99久久久久久久久| 久久久精品黄色| 熟妇人妻无乱码中文字幕真矢织江| 性欧美lx╳lx╳| 日韩免费av一区二区| 国产爆初菊在线观看免费视频网站| 色偷偷一区二区三区| 永久免费毛片在线观看| 美女国产一区二区| 正在播放亚洲| 日韩在线网址| 91福利视频在线观看| 欧美伦理影视网| 欧美亚日韩国产aⅴ精品中极品| av永久免费观看| 久久国产成人午夜av影院| 一区二区视频在线观看| 国产精区一区二区| 欧美激情一级精品国产| 少妇高潮一区二区三区99小说| 精品久久久久久久久久国产| 国内精品卡一卡二卡三| 精品一区二区三区的国产在线播放| 在线观看污视频| 精品在线网站观看| 青青a在线精品免费观看| 91女主播在线观看| 91精品婷婷国产综合久久| 国产精品不卡av| 久久久久国产一区二区三区四区 | 激情中国色综合| 九九精品在线播放| 午夜av免费在线观看| 欧美在线短视频| 清纯粉嫩极品夜夜嗨av| 久久这里只有精品首页| 91小视频在线播放| 亚洲国产99| 亚洲激情一区二区| 精品亚洲自拍| 成人精品一区二区三区电影免费 | 国产精品稀缺呦系列在线| 国产一二区在线| 亚洲女人天堂成人av在线| 97精品人妻一区二区三区香蕉| 亚洲午夜精品17c| 高清国产在线观看| 成人av在线播放网址| 91制片厂毛片| 日韩午夜激情| 一级全黄肉体裸体全过程| 思热99re视热频这里只精品| 成人福利视频网| 黑人精品一区| 久久久久国产精品免费| 在线视频91p| 亚洲精品一区二区三区99| 最近中文在线观看| 精品国产1区2区| 日本a级片视频| 国产精品视频九色porn| 亚洲成av人片在线观看无| 看电视剧不卡顿的网站| 日本在线观看a| 伊人精品成人久久综合软件| 熟妇熟女乱妇乱女网站| 激情五月色综合国产精品| 国产一区二区在线观看免费播放| 国产午夜久久av| 国产精品日韩在线播放| 国产高清不卡| 91精品国产高清| 色在线视频网| 欧美xxxx18国产| 国产在线观看91| 色综合亚洲精品激情狠狠| 精品无人乱码| 亚洲美女av黄| 天堂视频中文在线| 精品国产精品网麻豆系列| 国产男男gay网站| 欧美区一区二区三区| 99re热视频| 欧美性videosxxxxx| 五月天激情四射| 日韩欧美第一页| 青青视频在线免费观看| 日韩欧美极品在线观看| 日韩精品一区二区三| 亚洲成在线观看| 国产一级二级三级| 亚洲国产精品影院| 日韩免费av片| 精品久久香蕉国产线看观看亚洲 | 全国精品久久少妇| www日韩在线观看| 日韩av在线播放中文字幕| 国产成人精品视频ⅴa片软件竹菊| 国产精品色网| 无码人妻丰满熟妇区毛片18| 国产农村妇女毛片精品久久莱园子| 少妇高潮喷水在线观看| 亚洲色诱最新| 999香蕉视频| 奇米色一区二区三区四区| 亚洲欧美自偷自拍另类| 麻豆国产欧美一区二区三区| 午夜剧场高清版免费观看| 精品一区二区三区影院在线午夜 | eeuss鲁片一区二区三区| 国产精品久久久久久久久久直播| 国产欧美三级电影| 久久久久久久久久久久久9999| 精品中文字幕一区二区三区av| 欧美综合77777色婷婷| 首页国产精品| 国产一级做a爰片久久毛片男| 国产亚洲毛片在线| 中文字幕亚洲专区| 91精品一区二区| 免费看污污视频| 成人性生交视频免费观看| 美女欧美视频在线观看免费| 欧美日韩在线精品一区二区三区激情| 中文字幕精品在线观看| 欧美精品一级二级| av高清一区二区| 亚洲精品国产精品久久清纯直播| 欧美精品少妇| 久久亚洲精品一区二区| 成人性生交大片免费看网站 | 九九久久免费视频| 亚洲国产欧美在线| 天天射天天干天天| 校园春色综合网| 日韩精品一区二区三区电影| 日韩午夜av在线| 一区二区三区 欧美| 国产成人精品免费网站| 我和岳m愉情xxxⅹ视频| 亚洲视频免费在线观看| 日韩av大片在线观看| 在线播放中文一区| 亚洲av成人精品毛片| 色偷偷av一区二区三区乱| 大桥未久在线视频| 成人做爰www免费看视频网站| 亚州国产精品| 日本黄xxxxxxxxx100| 鲁大师成人一区二区三区| 亚洲综合中文网| 中文字幕成人网| 日本视频免费在线| 日韩一区二区三区电影在线观看| 欧美孕妇性xxxⅹ精品hd| 久久99视频免费| 亚洲精品555| 精品人伦一区二区三区| 午夜久久美女| 国产色视频在线播放| 91麻豆成人久久精品二区三区| 欧美精品久久久久久久久46p| 在线观看一区二区精品视频| 免费观看国产视频| 久久亚洲精品一区二区| 91p九色成人| 欧美成熟毛茸茸复古| 国产精品theporn| 国内av一区二区| 国产精品福利av| 一级特黄免费视频| 日韩福利视频在线观看| 欧美xxxx做受欧美88bbw| 91精品国产综合久久久久久久久 | 亚洲欧美变态国产另类| 99在线视频影院| eeuss一区二区三区| 亚洲v在线看| 91插插插影院| 最新国产成人在线观看| 中国女人一级一次看片| 亚洲视屏在线播放| 久久人体大尺度| 蜜桃欧美视频| 中文精品视频| 亚洲色图14p| 欧美日韩国产精品一区二区三区四区| 成人爽a毛片一区二区| 欧美国产日韩免费| 视频精品一区二区三区| 日韩欧美视频免费在线观看| 国产乱子伦一区二区三区国色天香| 亚洲波多野结衣| 91精品国产91久久综合桃花| 精产国品自在线www| 成人在线播放av| 亚洲乱码电影| 亚洲精品久久久久久| 亚洲午夜精品17c| 深爱激情五月婷婷| 欧美一级成年大片在线观看 | 亚洲人成啪啪网站| 激情开心成人网| 色视频一区二区三区| 老司机精品视频在线| 久久成人小视频| 欧美不卡一区二区三区| bl视频在线免费观看| 久久99精品久久久久久久久久| 免费欧美在线| 国产真人真事毛片视频| 91麻豆精品国产自产在线| 午夜伦理大片视频在线观看| 国产精品污www一区二区三区| 日韩午夜免费视频| 91成人在线免费视频| 欧美乱妇15p| 黄色在线观看视频网站| 欧美日本韩国一区二区三区| 秋霞影院一区二区| 欧美又粗又大又长| 亚洲国产精品久久91精品| 女生影院久久| 中文字幕精品一区日韩| 岛国精品在线观看| 黄色片视频免费| 伦理中文字幕亚洲| 精品久久对白| 8x8x最新地址| 一区二区三区四区高清精品免费观看 | 在线网址91| 欧美日韩精品久久久免费观看| 久久精品国产99久久6| 九九热精品免费视频| 亚洲开心激情网| 二区三区精品| 狠狠爱免费视频| 亚洲美腿欧美偷拍| 天堂网www中文在线| 91日本在线观看| 久久久人人人| 欧美成人国产精品高潮| 亚洲色图欧美制服丝袜另类第一页| www 久久久| 国产精品第12页| 夜夜精品浪潮av一区二区三区| 国产最新视频在线| 官网99热精品| 美女脱光内衣内裤视频久久网站| 国产乡下妇女做爰视频|