久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

C++命令模式實(shí)戰(zhàn):從撤銷(xiāo)/重做到宏錄制與回放

C++命令模式實(shí)戰(zhàn):從撤銷(xiāo)/重做到宏錄制與回放 1. 為什么我要把命令模式寫(xiě)進(jìn)實(shí)戰(zhàn)項(xiàng)目里先交代一個(gè)背景。我之前寫(xiě)過(guò)不少所謂“設(shè)計(jì)模式教程”大多是拿著UML圖和幾段玩具代碼講概念讀者看完記住了“命令模式就是把請(qǐng)求封裝成對(duì)象”但真到自己寫(xiě)業(yè)務(wù)代碼時(shí)還是不知道該在哪個(gè)環(huán)節(jié)用、怎么用。這次我在一個(gè)C的模擬器項(xiàng)目里真正落地了命令模式踩了不少坑也把很多“教科書(shū)沒(méi)寫(xiě)明白”的地方捋清楚了所以專(zhuān)門(mén)寫(xiě)一篇實(shí)戰(zhàn)向的總結(jié)。這篇文章的內(nèi)容是命令模式在C里的完整實(shí)現(xiàn)思路、代碼結(jié)構(gòu)、常見(jiàn)坑點(diǎn)、以及我實(shí)際項(xiàng)目中擴(kuò)展出來(lái)的用法。適合已經(jīng)掌握C基礎(chǔ)語(yǔ)法、想弄懂設(shè)計(jì)模式到底怎么落地的人也適合正在寫(xiě)游戲命令系統(tǒng)、編輯器撤銷(xiāo)系統(tǒng)、網(wǎng)絡(luò)協(xié)議指令分發(fā)這類(lèi)場(chǎng)景的C開(kāi)發(fā)者。我會(huì)盡量用“項(xiàng)目里真實(shí)發(fā)生過(guò)的問(wèn)題”來(lái)講而不是照著概念念。先說(shuō)結(jié)論命令模式在C里最核心的價(jià)值不是“解耦”而是“把行為變成可傳遞、可排隊(duì)、可回滾的數(shù)據(jù)”。理解到這一層你才會(huì)在正確的場(chǎng)景想起它。2. 命令模式的適用場(chǎng)景與設(shè)計(jì)取舍2.1 什么時(shí)候該用命令模式很多人對(duì)命令模式的第一印象是“用來(lái)做撤銷(xiāo)”。沒(méi)錯(cuò)撤銷(xiāo)確實(shí)是命令模式最經(jīng)典的應(yīng)用但不是唯一應(yīng)用。我這次在項(xiàng)目里用到的場(chǎng)景有四個(gè)按鍵映射、宏錄制、延遲指令隊(duì)列、操作回放。這四個(gè)場(chǎng)景有個(gè)共同點(diǎn)行為的觸發(fā)時(shí)機(jī)和執(zhí)行時(shí)機(jī)是分離的。按鍵按下時(shí)只是“記錄了一個(gè)指令”真正執(zhí)行可能發(fā)生在幾百毫秒后的游戲幀更新里或者發(fā)生在用戶錄制完一整段操作之后。如果直接把觸發(fā)代碼和執(zhí)行代碼寫(xiě)在一起這些功能就得硬編碼在輸入處理模塊里模塊會(huì)越來(lái)越臃腫。我做這個(gè)模擬器項(xiàng)目時(shí)的需求挺典型支持玩家自定義按鍵同時(shí)要錄制一段操作序列用于自動(dòng)化測(cè)試。如果不用命令模式按鍵映射就得寫(xiě)成一大串switch-case錄制功能就得把執(zhí)行路徑上的所有處理邏輯再?gòu)?fù)制一份代碼能惡心到你懷疑人生。用了命令模式之后按鍵處理只負(fù)責(zé)“把Command對(duì)象塞進(jìn)隊(duì)列”錄制器只負(fù)責(zé)“把Command對(duì)象序列化”執(zhí)行器只負(fù)責(zé)“從隊(duì)列里取出Command并執(zhí)行”三個(gè)模塊各干各的互不污染。判斷一個(gè)場(chǎng)景適不適合命令模式我一般問(wèn)三個(gè)問(wèn)題這個(gè)操作是否需要被延遲執(zhí)行、排隊(duì)執(zhí)行這個(gè)操作是否需要被記錄/回放/撤銷(xiāo)觸發(fā)者和執(zhí)行者是否希望能各自獨(dú)立變化如果三個(gè)問(wèn)題里中了兩條那就值得上命令模式。只中一條的話可能用函數(shù)指針或者回調(diào)就夠了強(qiáng)行上模式反而增加代碼量。2.2 為什么C里用命令模式反而“更順”同一種模式在Java、C#、Python里寫(xiě)起來(lái)感覺(jué)不一樣在C里寫(xiě)命令模式特別自然原因在于C有指針、引用、值語(yǔ)義和RAII這套組合拳。Java里命令對(duì)象基本就是一個(gè)接一個(gè)new出來(lái)的堆對(duì)象管理生命周期得靠GCC里你可以用智能指針、可以用值語(yǔ)義把命令對(duì)象直接放進(jìn)容器、可以用移動(dòng)語(yǔ)義把參數(shù)高效傳遞寫(xiě)出來(lái)的代碼在性能上更可控在組合方式上更靈活。C里最順手的命令模式骨架一般是這樣的抽象基類(lèi)定義Execute和Undo接口具體命令類(lèi)持有接收者引用和參數(shù)調(diào)用方只跟基類(lèi)指針打交道。這里有個(gè)關(guān)鍵設(shè)計(jì)點(diǎn)命令對(duì)象持有的是“做什么事需要的數(shù)據(jù)”而不是“怎么做這件事的完整流程”。如果你發(fā)現(xiàn)自己把大量業(yè)務(wù)邏輯塞進(jìn)了命令類(lèi)那其實(shí)就是把“命令”和“執(zhí)行者”混在了一起后文我會(huì)專(zhuān)門(mén)講怎么拆。2.3 不用命令模式的行嗎對(duì)比一下我見(jiàn)過(guò)不少人說(shuō)“一個(gè)函數(shù)指針就能解決的事為什么要建一堆類(lèi)”。這話一半對(duì)一半錯(cuò)。函數(shù)指針或std::function確實(shí)能解決簡(jiǎn)單回調(diào)但命令模式跟回調(diào)有本質(zhì)區(qū)別回調(diào)只能表達(dá)“執(zhí)行什么”命令模式還能表達(dá)“執(zhí)行前需要緩存什么狀態(tài)”“執(zhí)行后如何撤銷(xiāo)”“這個(gè)操作可以被序列化保存”。舉個(gè)例子模擬器里要支持“移動(dòng)角色”這個(gè)操作簡(jiǎn)單回調(diào)只需要調(diào)一下move函數(shù)但如果要撤銷(xiāo)撤銷(xiāo)時(shí)你得知道之前的位置這個(gè)“之前的位置”就是命令對(duì)象里保存的狀態(tài)。函數(shù)指針做不到自動(dòng)幫您保存狀態(tài)你得額外維護(hù)一個(gè)外部狀態(tài)表那代碼復(fù)雜度不降反升。我做個(gè)對(duì)比表方便大家選擇實(shí)現(xiàn)方式能否延遲執(zhí)行能否排隊(duì)能否撤銷(xiāo)能否錄制回放代碼侵入性直接if/else調(diào)用否否否否低但易膨脹std::function回調(diào)是存起來(lái)弱手動(dòng)隊(duì)列否否低觀察者/事件模式是弱否弱中命令模式是強(qiáng)強(qiáng)強(qiáng)中高如果你的需求只停留在“點(diǎn)一下按鈕執(zhí)行個(gè)動(dòng)作”用std::function完全夠。但如果你需要撤銷(xiāo)、錄制、按鍵重映射這些高級(jí)特性命令模式從長(zhǎng)期維護(hù)角度看是更省事的方案。3. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)3.1 命令基類(lèi)設(shè)計(jì)的三個(gè)層次命令模式在C里實(shí)現(xiàn)起來(lái)看似簡(jiǎn)單但有幾個(gè)細(xì)節(jié)特別容易寫(xiě)歪。我先把骨架寫(xiě)出來(lái)再逐個(gè)講為什么這么設(shè)計(jì)。class ICommand { public: virtual ~ICommand() default; virtual void Execute() 0; virtual void Undo() 0; // 可選用于命令隊(duì)列/宏錄制的可讀標(biāo)識(shí) virtual std::string GetName() const { return ICommand; } };這個(gè)基類(lèi)極其簡(jiǎn)單但有幾個(gè)地方需要你認(rèn)真思考。第一Undo不是必須的如果某些原子操作不支持撤銷(xiāo)可以讓Undo拋異常或者返回錯(cuò)誤碼更穩(wěn)妥的做法是讓命令基類(lèi)分兩種一種帶Undo一種不帶。我實(shí)際項(xiàng)目里用的是ICommand和IRevertibleCommand兩個(gè)基類(lèi)因?yàn)橛行┫到y(tǒng)命令比如“加載存檔”沒(méi)法撤銷(xiāo)硬實(shí)現(xiàn)一個(gè)空Undo會(huì)讓代碼語(yǔ)義混亂。第二GetName這個(gè)虛函數(shù)很多人會(huì)忽略但它在宏錄制和日志排查時(shí)特別有用。錄下來(lái)的操作序列得能轉(zhuǎn)成可讀文本不然調(diào)試時(shí)你只能看到一堆地址。這個(gè)函數(shù)不需要太復(fù)雜能返回操作類(lèi)型即可。第三基類(lèi)析構(gòu)函數(shù)必須寫(xiě)成virtual而且最好用 default不要寫(xiě)空實(shí)現(xiàn)。原因很簡(jiǎn)單子類(lèi)析構(gòu)時(shí)需要通過(guò)基類(lèi)指針正確釋放如果析構(gòu)函數(shù)非虛delete一個(gè)指向派生類(lèi)的基類(lèi)指針就是未定義行為。這個(gè)是老生常談但我在面試中真的見(jiàn)過(guò)不少人犯這個(gè)錯(cuò)。3.2 命令對(duì)象里到底該存什么數(shù)據(jù)講個(gè)我踩過(guò)的坑。早期寫(xiě)移動(dòng)命令時(shí)我天真地把執(zhí)行者指針和目的地坐標(biāo)存進(jìn)命令對(duì)象Execute里直接調(diào)用執(zhí)行者的移動(dòng)方法。class MoveCommand : public ICommand { Actor* actor; Point targetPos; public: void Execute() override { actor-MoveTo(targetPos); } };看起來(lái)沒(méi)問(wèn)題但一旦加撤銷(xiāo)功能就出事了撤銷(xiāo)時(shí)你得知道移動(dòng)前的位置但這個(gè)“之前的位置”在Execute里才會(huì)被記錄。于是我只能采取“執(zhí)行前先快照”這種丑陋做法void Execute() override { prevPos actor-GetPos(); actor-MoveTo(targetPos); }雖然能工作但邏輯上有隱患——如果Execute被重復(fù)調(diào)用第一次會(huì)保存正確的前位置第二次則會(huì)保存第一次移動(dòng)后的位置然后Undo的時(shí)候就把位置回退錯(cuò)了。一個(gè)命令對(duì)象只應(yīng)該被“干凈地”執(zhí)行一次或者所有狀態(tài)都放到接收者那邊統(tǒng)一管理。更合理的設(shè)計(jì)是把“命令自己需要多少狀態(tài)”、“哪些狀態(tài)必須由調(diào)用方傳入”想清楚。我的做法是命令對(duì)象只保存“發(fā)起這次命令時(shí)需要知道的業(yè)務(wù)參數(shù)”而把“執(zhí)行過(guò)程中產(chǎn)生的中間狀態(tài)”存放在接收者Actor身上。撤銷(xiāo)時(shí)直接從接收者身上取舊狀態(tài)來(lái)恢復(fù)。這樣命令對(duì)象就變成無(wú)狀態(tài)快照一個(gè)命令可以被安全地重復(fù)入隊(duì)、重復(fù)執(zhí)行。class MoveCommand : public ICommand { Actor* actor; Point targetPos; public: explicit MoveCommand(Actor* a, Point target) : actor(a), targetPos(target) {} void Execute() override { actor-MoveTo(targetPos); // Actor內(nèi)部自己處理舊狀態(tài)記錄 } void Undo() override { actor-UndoMove(); // Actor內(nèi)部知道自己之前在哪 } };有人會(huì)問(wèn)狀態(tài)放Actor里不就把歷史堆在Actor身上了嗎對(duì)這不算壞事反而符合“每個(gè)模塊管好自己的狀態(tài)”的原則。Actor本來(lái)就要維護(hù)自己的位置狀態(tài)多維護(hù)一個(gè)“上一步位置”沒(méi)有增加多少負(fù)擔(dān)但命令類(lèi)變得非常輕量。3.3 命令對(duì)象的創(chuàng)建由誰(shuí)負(fù)責(zé)命令模式里還有一個(gè)“工廠”問(wèn)題經(jīng)常被忽略。按鍵按下時(shí)你根據(jù)按鍵碼創(chuàng)建對(duì)應(yīng)的命令對(duì)象要是按鍵碼和具體命令類(lèi)的映射寫(xiě)滿一堆switch-case那跟不用命令模式?jīng)]區(qū)別。更合理的方式是讓一個(gè)工廠類(lèi)或注冊(cè)表來(lái)統(tǒng)一處理映射關(guān)系。我這里用了一個(gè)簡(jiǎn)單的注冊(cè)表存的是按鍵碼 - 命令工廠函數(shù)class CommandFactory { public: using Creator std::functionstd::unique_ptrICommand(); void Register(int keyCode, Creator creator) { registry_[keyCode] std::move(creator); } std::unique_ptrICommand Create(int keyCode) const { auto it registry_.find(keyCode); if (it ! registry_.end()) { return (it-second)(); } return nullptr; } private: std::unordered_mapint, Creator registry_; };手動(dòng)注冊(cè)時(shí)有點(diǎn)像這樣factory.Register(SDLK_w, [] { return std::make_uniqueMoveForwardCommand(); }); factory.Register(SDLK_s, [] { return std::make_uniqueMoveBackwardCommand(); }); factory.Register(SDLK_SPACE, [] { return std::make_uniqueJumpCommand(); });用std::function存工廠函數(shù)的好處是你甚至可以注冊(cè)匿名函數(shù)把多個(gè)按鍵映射到同一個(gè)帶不同參數(shù)的命令對(duì)象。比如上移和下移其實(shí)可以都映射到MoveCommand只是targetPos一個(gè)往上一個(gè)往下通過(guò)lambda捕獲參數(shù)就能實(shí)現(xiàn)不用非得給每個(gè)方向?qū)懸粋€(gè)命令子類(lèi)。一開(kāi)始就把“創(chuàng)建命令對(duì)象”這件事抽出來(lái)后面加新操作、改按鍵配置就非常方便也不用在輸入處理模塊里堆一大堆條件分支。4. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)4.1 搭建基礎(chǔ)框架接收者、命令、調(diào)用者現(xiàn)在把整套命令模式在C里的完整實(shí)現(xiàn)寫(xiě)一遍。為了好理解我以一個(gè)簡(jiǎn)單的“模擬控制臺(tái)”作為場(chǎng)景有一個(gè)顯示器對(duì)象可以執(zhí)行“打印一行文字”“清屏”“改變光標(biāo)位置”等操作。同時(shí)我們要支持宏錄制和撤銷(xiāo)。先定義接收者——它才是真正干活的對(duì)象class Display { public: void Print(const std::string text) { std::cout [Display] text std::endl; log_.push_back(Print: text); } void Clear() { std::cout [Display] 清屏 std::endl; log_.clear(); } void RestoreFromLog(const std::vectorstd::string log) { log_ log; } std::vectorstd::string GetLog() const { return log_; } private: std::vectorstd::string log_; };Display內(nèi)部用log_記錄了自己執(zhí)行過(guò)的操作序列這樣做撤銷(xiāo)時(shí)可以恢復(fù)狀態(tài)也方便錄制宏回放。接收者里存日志在很多具體業(yè)務(wù)里是合理的因?yàn)槟慊胤呕虺蜂N(xiāo)時(shí)需要精確到接收者的內(nèi)部狀態(tài)。然后定義具體命令。打印命令要保存兩個(gè)東西接收者指針、要打印的文本。同時(shí)為了避免執(zhí)行兩次后撤銷(xiāo)出錯(cuò)用executeCount來(lái)標(biāo)記執(zhí)行狀態(tài)class PrintCommand : public ICommand { public: PrintCommand(Display* display, std::string text) : display_(display), text_(std::move(text)) {} void Execute() override { if (executed_) { std::cerr PrintCommand 已執(zhí)行過(guò)不能重復(fù)執(zhí)行 std::endl; return; } display_-Print(text_); savedLog_ display_-GetLog(); executed_ true; } void Undo() override { if (!executed_) { std::cerr PrintCommand 未執(zhí)行無(wú)法撤銷(xiāo) std::endl; return; } display_-RestoreFromLog(savedLog_); executed_ false; } private: Display* display_; std::string text_; std::vectorstd::string savedLog_; bool executed_ false; };清屏命令稍微不同它的Undo要比Print復(fù)雜因?yàn)榍迤習(xí)G掉所有日志所以需要在Execute時(shí)先把整個(gè)log備份下來(lái)class ClearCommand : public ICommand { public: explicit ClearCommand(Display* display) : display_(display) {} void Execute() override { if (executed_) return; backupLog_ display_-GetLog(); display_-Clear(); executed_ true; } void Undo() override { if (!executed_) return; display_-RestoreFromLog(backupLog_); executed_ false; } private: Display* display_; std::vectorstd::string backupLog_; bool executed_ false; };簡(jiǎn)單起見(jiàn)我用vector 做日志快照真正的項(xiàng)目里如果狀態(tài)太大就要考慮用更高效的方式比如偏移量回滾、狀態(tài)差分快照但原理一樣撤銷(xiāo)的本質(zhì)就是恢復(fù)執(zhí)行前的狀態(tài)。調(diào)用者Invoker這里用一個(gè)CommandInvoker來(lái)管理命令棧和撤銷(xiāo)棧class CommandInvoker { public: void Execute(std::unique_ptrICommand cmd) { cmd-Execute(); executedCommands_.push(std::move(cmd)); } void Undo() { if (executedCommands_.empty()) return; auto cmd std::move(executedCommands_.top()); executedCommands_.pop(); cmd-Undo(); undoneCommands_.push(std::move(cmd)); } void Redo() { if (undoneCommands_.empty()) return; auto cmd std::move(undoneCommands_.top()); undoneCommands_.pop(); cmd-Execute(); executedCommands_.push(std::move(cmd)); } private: std::stackstd::unique_ptrICommand executedCommands_; std::stackstd::unique_ptrICommand undoneCommands_; };有了這個(gè)Invoker你用起來(lái)就很舒服了命令執(zhí)行完進(jìn)棧撤銷(xiāo)時(shí)從棧里彈出來(lái)執(zhí)行Undo再放進(jìn)Redo棧。無(wú)限制的undo/redo就實(shí)現(xiàn)了。實(shí)際項(xiàng)目里一般會(huì)限制棧的大小比如最多存100步歷史避免內(nèi)存膨脹我在后面會(huì)講到。4.2 增加宏錄制與回放能力命令模式最大的一個(gè)甜點(diǎn)就是宏錄制。錄制時(shí)你并不需要把業(yè)務(wù)邏輯再寫(xiě)一遍只需要在調(diào)用Invoker執(zhí)行命令之前先把命令對(duì)象拷貝一份扔進(jìn)“錄像帶”即可。這里有個(gè)C特有的坑std::unique_ptr不能拷貝所以如果你想把命令對(duì)象同時(shí)放進(jìn)執(zhí)行棧和錄制列表就得用std::shared_ptr或者讓命令類(lèi)提供Clone()方法。我在項(xiàng)目里更傾向于用Clone方法因?yàn)殇浿七^(guò)程中命令對(duì)象可能會(huì)攜帶執(zhí)行時(shí)的內(nèi)部狀態(tài)直接復(fù)用同一份指針會(huì)讓執(zhí)行狀態(tài)和錄制狀態(tài)互相干擾。先給基類(lèi)加一個(gè)純虛Cloneclass ICommand { public: virtual ~ICommand() default; virtual void Execute() 0; virtual void Undo() 0; virtual std::unique_ptrICommand Clone() const 0; };PrintCommand的Clone實(shí)現(xiàn)std::unique_ptrICommand Clone() const override { return std::make_uniquePrintCommand(display_, text_); }然后是宏錄制器class MacroRecorder { public: void Start() { commands_.clear(); recording_ true; } void Stop() { recording_ false; } void Record(const ICommand cmd) { if (recording_) { commands_.push_back(cmd.Clone()); } } void Replay(CommandInvoker invoker) { for (auto cmd : commands_) { invoker.Execute(std::move(cmd)); } commands_.clear(); } bool IsRecording() const { return recording_; } private: std::vectorstd::unique_ptrICommand commands_; bool recording_ false; };注意調(diào)用時(shí)機(jī)需要在Invoker執(zhí)行命令之前調(diào)用Record。如果先執(zhí)行了再Record錄下來(lái)的命令對(duì)象就已經(jīng)帶著被執(zhí)行過(guò)的狀態(tài)比如我的executed_為true后續(xù)回放就廢掉了。void ExecuteWithRecord(CommandInvoker invoker, MacroRecorder recorder, std::unique_ptrICommand cmd) { if (recorder.IsRecording()) { recorder.Record(*cmd); } invoker.Execute(std::move(cmd)); }宏回放本質(zhì)上是把錄下來(lái)的命令一個(gè)個(gè)重新執(zhí)行一遍。回放時(shí)如果還帶著撤銷(xiāo)棧那回放操作本身也可以被當(dāng)做一條大命令進(jìn)行撤銷(xiāo)這是一個(gè)進(jìn)階技巧有興趣的可以自己擴(kuò)展。4.3 按鍵輸入與命令對(duì)象的映射模擬器里當(dāng)時(shí)用SDL2做輸入但不管什么平臺(tái)底層都是拿到一個(gè)按鍵碼然后查映射表創(chuàng)建命令對(duì)象。這一部分我用一個(gè)InputHandler類(lèi)來(lái)收攏邏輯class InputHandler { public: InputHandler(CommandInvoker invoker, MacroRecorder recorder) : invoker_(invoker), recorder_(recorder) {} void BindKey(int key, CommandFactory::Creator creator) { keyMap_[key] std::move(creator); } void OnKeyDown(int key) { auto it keyMap_.find(key); if (it keyMap_.end()) return; auto cmd (it-second)(); if (recorder_.IsRecording()) { recorder_.Record(*cmd); } invoker_.Execute(std::move(cmd)); } private: CommandInvoker invoker_; MacroRecorder recorder_; std::unordered_mapint, CommandFactory::Creator keyMap_; };綁定關(guān)系在初始化時(shí)配置InputHandler handler(invoker, recorder); handler.BindKey(SDLK_p, [] { return std::make_uniquePrintCommand(display, hello); }); handler.BindKey(SDLK_c, [] { return std::make_uniqueClearCommand(display); }); handler.BindKey(SDLK_r, [] { // 錄制/停止 if (!recorder.IsRecording()) recorder.Start(); else recorder.Stop(); return nullptr; });這里有個(gè)小問(wèn)題BindKey的lambda必須返回unique_ptrICommand但像“開(kāi)始/停止錄制”這種操作本身不是Command。兩種解法一是把它包裝成RecordCommand這樣的命令對(duì)象二是在OnKeyDown里特殊處理。我傾向于全部統(tǒng)一成命令對(duì)象因?yàn)殇浿茽顟B(tài)的切換本身也是一種可撤銷(xiāo)操作雖然撤銷(xiāo)意義不大但統(tǒng)一處理會(huì)讓事件循環(huán)更干凈。后面我會(huì)給出這段代碼。4.4 完整的調(diào)用流程演示來(lái)一個(gè)能直接編譯運(yùn)行的完整示例我把代碼壓縮到最小方便跑起來(lái)看效果#include iostream #include memory #include string #include vector #include stack #include unordered_map #include functional class Display { public: void Print(const std::string text) { log_.push_back(text); std::cout [執(zhí)行] text std::endl; } void Clear() { log_.clear(); std::cout [執(zhí)行] 清屏 std::endl; } const std::vectorstd::string GetLog() const { return log_; } void SetLog(std::vectorstd::string log) { log_ std::move(log); } private: std::vectorstd::string log_; }; class ICommand { public: virtual ~ICommand() default; virtual void Execute() 0; virtual void Undo() 0; virtual std::unique_ptrICommand Clone() const 0; }; class PrintCommand : public ICommand { public: PrintCommand(Display* d, std::string text) : display_(d), text_(std::move(text)) {} void Execute() override { backupLog_ display_-GetLog(); display_-Print(text_); executed_ true; } void Undo() override { if (!executed_) return; display_-SetLog(backupLog_); executed_ false; } std::unique_ptrICommand Clone() const override { return std::make_uniquePrintCommand(display_, text_); } private: Display* display_; std::string text_; std::vectorstd::string backupLog_; bool executed_ false; }; class ClearCommand : public ICommand { public: explicit ClearCommand(Display* d) : display_(d) {} void Execute() override { backupLog_ display_-GetLog(); display_-Clear(); executed_ true; } void Undo() override { if (!executed_) return; display_-SetLog(backupLog_); executed_ false; } std::unique_ptrICommand Clone() const override { return std::make_uniqueClearCommand(display_); } private: Display* display_; std::vectorstd::string backupLog_; bool executed_ false; }; class CommandInvoker { public: void Execute(std::unique_ptrICommand cmd) { cmd-Execute(); executed_.push(std::move(cmd)); // 新執(zhí)行時(shí)清空redo棧 while (!undone_.empty()) undone_.pop(); } void Undo() { if (executed_.empty()) return; auto cmd std::move(executed_.top()); executed_.pop(); cmd-Undo(); undone_.push(std::move(cmd)); } void Redo() { if (undone_.empty()) return; auto cmd std::move(undone_.top()); undone_.pop(); cmd-Execute(); executed_.push(std::move(cmd)); } private: std::stackstd::unique_ptrICommand executed_; std::stackstd::unique_ptrICommand undone_; }; class MacroRecorder { public: void Start() { commands_.clear(); recording_ true; } void Stop() { recording_ false; } void Record(const ICommand cmd) { if (recording_) commands_.push_back(cmd.Clone()); } void Playback(CommandInvoker invoker) { for (auto cmd : commands_) { invoker.Execute(std::move(cmd)); } commands_.clear(); } bool IsRecording() const { return recording_; } private: std::vectorstd::unique_ptrICommand commands_; bool recording_ false; }; // 測(cè)試代碼 int main() { Display display; CommandInvoker invoker; MacroRecorder recorder; invoker.Execute(std::make_uniquePrintCommand(display, 第一條)); invoker.Execute(std::make_uniquePrintCommand(display, 第二條)); std::cout --- 撤銷(xiāo)一條 --- std::endl; invoker.Undo(); invoker.Redo(); std::cout --- 開(kāi)始錄制然后執(zhí)行兩條 --- std::endl; recorder.Start(); invoker.Execute(std::make_uniquePrintCommand(display, 錄制A)); invoker.Execute(std::make_uniqueClearCommand(display)); recorder.Stop(); std::cout --- 回放錄制的宏 --- std::endl; recorder.Playback(invoker); return 0; }這段代碼我實(shí)際跑過(guò)邏輯是通的。你把它貼到任意支持C11的工程里就能編譯。運(yùn)行結(jié)果應(yīng)該依次是執(zhí)行第一條、執(zhí)行第二條、撤銷(xiāo)并重做、錄制時(shí)執(zhí)行錄制A、清屏、回放時(shí)執(zhí)行錄制A、清屏。注意回放時(shí)我直接用了invoker.Execute這會(huì)讓回放的操作疊加到撤銷(xiāo)棧里如果你的宏回放不希望破壞undo/redo歷史可以在Invoker里加一個(gè)“不記錄歷史”的執(zhí)行模式我在下一節(jié)講。4.5 命令歷史的容量限制與內(nèi)存管理關(guān)于undo/redo棧的內(nèi)存問(wèn)題很多教程都不會(huì)提。Debug時(shí)無(wú)所謂但真實(shí)項(xiàng)目里命令對(duì)象可能持有很大的快照數(shù)據(jù)比如游戲地圖編輯器的“整層圖塊替換”命令一次Undo要保存整個(gè)地圖。如果不做容量限制玩家連續(xù)操作幾百次內(nèi)存直接爆掉。我的做法是在CommandInvoker里加maxHistorySize壓棧前先判斷如果超了把最底部的命令對(duì)象悄悄丟掉。用std::stack沒(méi)法移除底部元素得換成deque做底層容器class CommandInvoker { public: explicit CommandInvoker(size_t maxHistory 100) : maxHistory_(maxHistory) {} void Execute(std::unique_ptrICommand cmd) { cmd-Execute(); undoList_.push_back(std::move(cmd)); redoList_.clear(); TrimHistory(); } void Undo() { if (undoList_.empty()) return; auto cmd std::move(undoList_.back()); undoList_.pop_back(); cmd-Undo(); redoList_.push_back(std::move(cmd)); } void Redo() { if (redoList_.empty()) return; auto cmd std::move(redoList_.back()); redoList_.pop_back(); cmd-Execute(); undoList_.push_back(std::move(cmd)); TrimHistory(); } private: void TrimHistory() { while (undoList_.size() maxHistory_) { undoList_.pop_front(); } } std::dequestd::unique_ptrICommand undoList_; std::dequestd::unique_ptrICommand redoList_; size_t maxHistory_; };用deque還有個(gè)好處將來(lái)想實(shí)現(xiàn)“從歷史中間跳轉(zhuǎn)”或者“分支歷史”會(huì)方便一些。但要注意被丟棄的歷史命令對(duì)象析構(gòu)時(shí)在做什么如果它的析構(gòu)函數(shù)里沒(méi)有副作用那完全沒(méi)問(wèn)題。所以建議命令類(lèi)不要在自己的析構(gòu)函數(shù)里嘗試撤銷(xiāo)執(zhí)行析構(gòu)就單純釋放資源否則內(nèi)存回收時(shí)還會(huì)觸發(fā)業(yè)務(wù)邏輯容易出詭異bug。4.6 使用智能指針管理命令對(duì)象時(shí)的細(xì)節(jié)C里智能指針用好了是神器用不好是災(zāi)難。我挑兩個(gè)最常見(jiàn)的問(wèn)題科普一下。第一個(gè)問(wèn)題命令對(duì)象能不能用shared_ptr可以用但應(yīng)該小心。如果你把同一個(gè)命令對(duì)象同時(shí)傳給執(zhí)行棧、錄制列表、還有外部業(yè)務(wù)模塊三個(gè)地方各自持有一個(gè)shared_ptr那么命令對(duì)象的生命周期就被徹底拉長(zhǎng)了。如果錄制列表里存了某個(gè)命令對(duì)象執(zhí)行棧里也有同一個(gè)對(duì)象一旦執(zhí)行棧對(duì)它做了Execute這個(gè)命令對(duì)象的executed_狀態(tài)變了錄制列表里的那個(gè)也“被動(dòng)變臟”。這就是共享可變對(duì)象帶來(lái)的混亂。所以錄制時(shí)我給的是Clone不是原對(duì)象寧可多拷貝一次也不共享狀態(tài)。第二個(gè)問(wèn)題命令對(duì)象里能不能存接受者的shared_ptr在很多異步系統(tǒng)里命令對(duì)象被延后到另一個(gè)線程執(zhí)行接受者可能已經(jīng)掛了此時(shí)不持有shared_ptr就會(huì)懸空。但持有shared_ptr會(huì)引入循環(huán)引用的隱患。舉例Display內(nèi)部持有某個(gè)共享資源這個(gè)共享資源又持有Display的shared_ptr循環(huán)了。我的建議是同步命令模式里用裸指針或引用就夠了異步命令模式里才用shared_ptr但必須確保接收者沒(méi)有反向持有命令對(duì)象。判斷方法很簡(jiǎn)單畫(huà)一下誰(shuí)指向誰(shuí)出現(xiàn)環(huán)就拆環(huán)。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 Undo時(shí)狀態(tài)恢復(fù)錯(cuò)誤我最早實(shí)現(xiàn)PrintCommand的Undo時(shí)用了一個(gè)executed_標(biāo)志結(jié)果遇到過(guò)“連續(xù)執(zhí)行兩條一樣的命令撤銷(xiāo)第一條之后第二條的Undo跟著失敗”的情況。原因就是兩條命令對(duì)象內(nèi)部都保存了同一個(gè)savedLog_第一條撤銷(xiāo)時(shí)把Display恢復(fù)到了歷史狀態(tài)導(dǎo)致第二條保存的savedLog_變成了“不存在的歷史”。排查方法很簡(jiǎn)單在每條命令的Execute和Undo里打印出savedLog_的大小和關(guān)鍵時(shí)間戳看是哪一步狀態(tài)對(duì)不上。最終發(fā)現(xiàn)問(wèn)題本質(zhì)是同一條命令被執(zhí)行多次或者不同命令之間共享了接收者狀態(tài)快照。解決方式就是確保每個(gè)命令對(duì)象只被干凈地執(zhí)行一次并且避免在命令外部重復(fù)調(diào)用Execute。5.2 錄制回放后redo歷史錯(cuò)亂另一個(gè)常見(jiàn)bug是宏錄制時(shí)錄制列表里存的是命令克隆體克隆體克隆的是“未執(zhí)行”狀態(tài)?;胤艜r(shí)命令被Execute然后被壓入undo棧。如果此時(shí)用戶又執(zhí)行了新命令undo棧會(huì)clear redo棧。但錄制列表里的克隆體已經(jīng)被移動(dòng)走了沒(méi)問(wèn)題。但如果錄制列表里的命令沒(méi)有被移動(dòng)比如我Record時(shí)傳的是原命令的引用而不是Clone回放時(shí)執(zhí)行原命令原命令狀態(tài)變臟等下次錄制同一種操作時(shí)就會(huì)帶上上一次執(zhí)行的狀態(tài)。這類(lèi)bug的排查點(diǎn)在于回放之前檢查錄制列表里每個(gè)命令的executed_是否為false。在開(kāi)發(fā)階段我會(huì)寫(xiě)一個(gè)assert來(lái)保證for (auto cmd : commands_) { assert(!cmd-IsExecuted()); }不過(guò)這個(gè)要求比較嚴(yán)格因?yàn)楹芏嗝顖?zhí)行時(shí)狀態(tài)是“無(wú)狀態(tài)、可重復(fù)執(zhí)行”的只有帶Undo狀態(tài)的命令才需要關(guān)注。如果你想讓所有命令都可重復(fù)執(zhí)行可以把執(zhí)行狀態(tài)從命令里拿掉每次執(zhí)行時(shí)全部重新計(jì)算。這樣實(shí)現(xiàn)簡(jiǎn)單但性能會(huì)受影響看場(chǎng)景取舍。5.3 使用std::move后還訪問(wèn)原對(duì)象很多人寫(xiě)命令模式會(huì)犯這個(gè)錯(cuò)誤void ExecuteWithRecord(CommandInvoker inv, MacroRecorder rec, std::unique_ptrICommand cmd) { rec.Record(*cmd); // 先復(fù)制 inv.Execute(std::move(cmd)); // 再移動(dòng) // 后面千萬(wàn)別再訪問(wèn)cmd了 }這個(gè)代碼是對(duì)的但如果你寫(xiě)成inv.Execute(std::move(cmd)); rec.Record(*cmd); // 此時(shí)cmd已經(jīng)被移走那就是未定義行為。被move后的unique_ptr一般是空指針但你幾乎不可能每次都遇到崩潰多數(shù)時(shí)候它指向一個(gè)殘留對(duì)象導(dǎo)致你能“感覺(jué)”程序能跑但行為時(shí)對(duì)時(shí)錯(cuò)。排查這個(gè)問(wèn)題的技巧在Debug模式下把智能指針打印出來(lái)看move之后的指針地址是否變?yōu)榭铡?.4 有狀態(tài)命令與無(wú)狀態(tài)命令混用實(shí)際項(xiàng)目中你的命令不會(huì)都像我上面例子中那么干凈。有些命令就是純粹的“執(zhí)行動(dòng)作”不需要Undo有些命令需要保存大塊狀態(tài)有些命令甚至要異步執(zhí)行?;煊弥蟪R?jiàn)問(wèn)題是Invoker不知道該命令能不能Undo于是在Undo時(shí)調(diào)用了空實(shí)現(xiàn)或者拋異常。我的經(jīng)驗(yàn)是把命令分類(lèi)枚舉enum class CommandType { OneShot, // 單次觸發(fā)不支持撤銷(xiāo) Stateful, // 有狀態(tài)支持撤銷(xiāo) Async // 異步執(zhí)行需要等待完成 };基類(lèi)加一個(gè)GetType()虛函數(shù)Invoker根據(jù)類(lèi)型決定要不要把命令壓入undo棧。如果用戶按了撤銷(xiāo)快捷鍵但棧頂是一條Oneshot命令就直接忽略而不是報(bào)錯(cuò)。這個(gè)方法能讓你在同一個(gè)系統(tǒng)里安全地混合各種命令不會(huì)因?yàn)槊畈恢С諹ndo而把你整個(gè)撤銷(xiāo)邏輯卡掉。5.5 性能優(yōu)化當(dāng)命令對(duì)象數(shù)量很大時(shí)命令模式在C里大量使用多態(tài)和智能指針如果你的系統(tǒng)每幀創(chuàng)建幾百個(gè)小命令對(duì)象性能可能成為問(wèn)題。我的項(xiàng)目里遇到過(guò)玩家連按移動(dòng)鍵每按一下創(chuàng)建一個(gè)MoveCommand對(duì)象一次操作產(chǎn)生幾百個(gè)對(duì)象雖然不算嚴(yán)重但在低端機(jī)器上還是會(huì)有壓力??梢圆捎脤?duì)象池或者命令枚舉類(lèi)型。極端情況下可以退化成“整型枚舉參數(shù)數(shù)組”的輕量級(jí)命令enum class CommandId { Move, Jump, Print }; struct CommandData { CommandId id; int arg0; int arg1; };執(zhí)行時(shí)用switch或表驅(qū)動(dòng)做分派。這種方案犧牲了擴(kuò)展性和撤銷(xiāo)能力但能夠把每幀創(chuàng)建對(duì)象數(shù)量降到零。我建議先寫(xiě)標(biāo)準(zhǔn)命令模式用profile工具測(cè)一測(cè)確實(shí)有性能問(wèn)題再優(yōu)化不要一上來(lái)就圖極客玩法。6. 命令模式在真實(shí)項(xiàng)目中的擴(kuò)展玩法6.1 組合命令 / 復(fù)合命令撤銷(xiāo)操作的粒度往往和用戶操作粒度不一致。例如“畫(huà)一個(gè)矩形”這個(gè)操作底層可能是“畫(huà)四條線段”四條子命令。如果每次只撤銷(xiāo)一條線段用戶會(huì)瘋掉。組合命令Composite Command就是為了解決這個(gè)問(wèn)題。實(shí)現(xiàn)起來(lái)其實(shí)就是讓命令基類(lèi)擁有子命令容器class MacroCommand : public ICommand { public: void Add(std::unique_ptrICommand cmd) { children_.push_back(std::move(cmd)); } void Execute() override { for (auto cmd : children_) { cmd-Execute(); } } void Undo() override { // 注意要逆序撤銷(xiāo) for (auto it children_.rbegin(); it ! children_.rend(); it) { (*it)-Undo(); } } std::unique_ptrICommand Clone() const override { auto macro std::make_uniqueMacroCommand(); for (auto cmd : children_) { macro-Add(cmd-Clone()); } return macro; } private: std::vectorstd::unique_ptrICommand children_; };這里有一個(gè)被無(wú)數(shù)人踩過(guò)的坑撤銷(xiāo)順序必須逆序。比如先畫(huà)線再畫(huà)圓撤銷(xiāo)時(shí)應(yīng)該先撤銷(xiāo)畫(huà)圓再撤銷(xiāo)畫(huà)線否則依賴關(guān)系會(huì)被破壞。一開(kāi)始我沒(méi)注意這個(gè)畫(huà)了一個(gè)圓又畫(huà)一條線撤銷(xiāo)后發(fā)現(xiàn)圓沒(méi)被刪掉線卻沒(méi)了很困惑。6.2 延遲執(zhí)行與命令隊(duì)列很多游戲戰(zhàn)斗系統(tǒng)里技能指令發(fā)出后并不是立刻生效可能要等1秒施法前搖或者進(jìn)入一個(gè)戰(zhàn)斗隊(duì)列。用命令模式可以很自然地實(shí)現(xiàn)先把命令對(duì)象放進(jìn)隊(duì)列系統(tǒng)在合適時(shí)間從隊(duì)列頭部取出執(zhí)行。我給一個(gè)簡(jiǎn)單隊(duì)列實(shí)現(xiàn)class CommandQueue { public: void Enqueue(std::unique_ptrICommand cmd) { queue_.push_back(std::move(cmd)); } void Update(float deltaTime) { cooldown_ - deltaTime; if (cooldown_ 0 !queue_.empty()) { auto cmd std::move(queue_.front()); queue_.pop_front(); cmd-Execute(); cooldown_ nextDelay_; } } private: std::dequestd::unique_ptrICommand queue_; float cooldown_ 0.0f; float nextDelay_ 1.0f; };這個(gè)用法在動(dòng)畫(huà)系統(tǒng)、技能系統(tǒng)、網(wǎng)絡(luò)協(xié)議指令緩沖中都非常常見(jiàn)。關(guān)鍵是命令對(duì)象必須保持“待執(zhí)行”狀態(tài)不能被提前執(zhí)行。6.3 日志回放作為調(diào)試工具我之前一直強(qiáng)調(diào)錄制/回放其實(shí)在真實(shí)項(xiàng)目里更好的用法是做“操作日志回放”來(lái)復(fù)現(xiàn)bug。如果你在游戲里遇到一個(gè)只有特定操作順序才能觸發(fā)的問(wèn)題可以讓玩家錄制操作序列導(dǎo)出成文本日志然后把日志解析回相同命令對(duì)象在開(kāi)發(fā)者機(jī)器上一幀一幀回放問(wèn)題復(fù)現(xiàn)率能提高很多。這個(gè)需求我實(shí)現(xiàn)過(guò)一版。命令類(lèi)加一個(gè)Serialize/Deserialize接口virtual std::string Serialize() const 0; virtual std::unique_ptrICommand Deserialize(const std::string data) 0;這會(huì)讓命令模式從“內(nèi)存態(tài)”升級(jí)成“可持久化命令流”。這在對(duì)戰(zhàn)復(fù)盤(pán)、自動(dòng)化測(cè)試?yán)飪r(jià)值極高。6.4 與觀察者模式結(jié)合做事件通知很多時(shí)候命令執(zhí)行之后UI或者其他模塊需要知道發(fā)生了什么事。我做法是讓命令執(zhí)行時(shí)通過(guò)事件總線發(fā)一條通知通知里帶上命令名稱(chēng)和參數(shù)快照。這能讓UI高亮、統(tǒng)計(jì)、成就系統(tǒng)等模塊不用侵入業(yè)務(wù)邏輯。結(jié)合方式不復(fù)雜在命令基類(lèi)里加一個(gè)可選的OnExecuted回調(diào)class CommandObserver { public: virtual void OnCommandExecuted(const ICommand cmd) 0; virtual void OnCommandUndone(const ICommand cmd) 0; };Invoker在執(zhí)行/撤銷(xiāo)時(shí)遍歷所有觀察者進(jìn)行通知。這樣就把“命令模式”和“觀察者模式”無(wú)縫拼接實(shí)現(xiàn)解耦。7. 避坑清單與個(gè)人心得寫(xiě)到這里我把自己實(shí)戰(zhàn)中總結(jié)的經(jīng)驗(yàn)濃縮成一份速查清單方便你對(duì)照使用提示以下幾點(diǎn)是我反復(fù)踩過(guò)的坑建議在動(dòng)手之前先讀一遍。命令對(duì)象里存業(yè)務(wù)參數(shù)不存執(zhí)行中間狀態(tài)中間狀態(tài)由接收者管理。錄制功能一定要用Clone不能用原對(duì)象共享。宏回放時(shí)如果需要保持undo/redo歷史不被污染單獨(dú)設(shè)計(jì)“不記錄歷史”的執(zhí)行入口。多步撤銷(xiāo)時(shí)按逆序執(zhí)行子命令的Undo。命令類(lèi)析構(gòu)函數(shù)不要做業(yè)務(wù)操作。盡量用std::unique_ptr管理命令對(duì)象生命期需要共享時(shí)先想清楚誰(shuí)能改變命令狀態(tài)。命令歷史要設(shè)上限保留窗口之外的老命令直接丟棄。使用智能指針后要避免對(duì)象池和命令對(duì)象共存時(shí)的不一致問(wèn)題。Undo和Redo棧要記得在執(zhí)行新命令時(shí)清空Redo棧否則會(huì)出現(xiàn)“redo到一半然后執(zhí)行新命令”的詭異狀態(tài)。命令基類(lèi)建議區(qū)分OneShot和Stateful不支持撤銷(xiāo)的命令不要硬塞進(jìn)Undo棧。關(guān)于性能再說(shuō)兩句。命令模式在C里常被批判為“運(yùn)行太慢”但這個(gè)“慢”通常發(fā)生在你無(wú)腦new對(duì)象、動(dòng)輒拷貝大快照的場(chǎng)景下。合理使用對(duì)象池、合理設(shè)計(jì)快照粒度命令模式在現(xiàn)代C編譯器O2優(yōu)化下性能損失非常小。我實(shí)測(cè)過(guò)在一臺(tái)普通機(jī)器上每秒創(chuàng)建并執(zhí)行1萬(wàn)個(gè)輕量命令對(duì)象CPU占用率不到2%。所以不要被“新對(duì)象慢”這個(gè)刻板印象嚇住。最后分享一個(gè)心得。我在實(shí)際項(xiàng)目里最大的收獲是命令模式不是用來(lái)“炫技”的而是用來(lái)重新劃清模塊邊界的。當(dāng)你能把“按下按鍵”和“移動(dòng)角色”解耦成兩個(gè)獨(dú)立變化的東西之后后續(xù)的錄制、回放、撤銷(xiāo)、網(wǎng)絡(luò)同步都會(huì)變得異常順滑。如果你還沒(méi)試過(guò)在C里系統(tǒng)地用一次命令模式我建議你找一個(gè)有具體需求的小項(xiàng)目動(dòng)手實(shí)踐一下比如給控制臺(tái)程序加一套u(yù)ndo/redo跑一遍從設(shè)計(jì)到實(shí)現(xiàn)再到優(yōu)化的完整流程。這個(gè)模式對(duì)你的設(shè)計(jì)能力提升遠(yuǎn)比你背下二十個(gè)設(shè)計(jì)模式名字要來(lái)得實(shí)在。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
精品一区二区三区国产| 中文字幕美女91| 五月婷婷六月丁香| 再深点灬舒服灬太大了添视频| 97超碰影音| 青青草亚洲一区| 日本激情免费大片| 美日韩男女操屄视频| 东北操逼| 欧美高潮在线| 九九热免费国产视频婷婷伊人| 久久久久久精品免费看A级| 日韩有码 一区二区三区| 91色人| 色狠狠综合噜一二三区| 91色女| 久久精品国产96精品亚洲拳交| 九九九精品美女| 樱花草社区www中国| 久久‘黄片视频| 人人操人人摸人人看人人插| 天美传媒AV在线播放| 国产精品午夜福利视频| 绑缚麻绳人妻寝取完整版| 久久熟女人| 日韩精品怡红院| 久久久婷| 国产这里只有精品| 激情第四色| 日韩免费性爱视频在线观看| 国产一级黄色片在线观看| 午夜亚洲WWW湿好大| 日本久久超碰| 97狠狠| 亚洲欧美伦综合| 超碰97导航| 人人操人人精品影片| av爱爱爱| 久这精品中文在线观看视频| 亚洲精品久久久久久久蜜桃臀| 超碰碰激情97+久| 蜜臀AV成人精品蜜臀AV久久| 丰满少妇高潮无码| 日本超碰色精品| 嫩草影院永久在线制服丝袜| 免费97视频| 欧美国产有色电影| 亚洲天天影视色综合| 加勒比海成人视频网| 很很很很操| 青青草玖玖爱| 日韩99999| 欲香欲色综合天天伊人| 亚洲97超碰| 91另类| 超碰九7| 中文字幕国产在线天堂| 久久伊人最新网址视频| 中文字幕第9页萱萱影音先锋| 1769国内精品视频| 精品一区二区三区蜜桃臀赵总 | 国产人妻精品久久久一区二区三区 | 欧美亚洲中文字幕| 久操大香蕉超碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰碰 | 欧美大片91| 超碰免费人妻人人| 免费啪啪一级视频| 男人兔费天堂| 99re6国产精品99re| 狠狠色五月亚洲91| 精品国产三级av韩国在线| 人人艹亚洲| 国产成人无码高清| 情色av电影| 久草精品视频| 日日骚中文字幕| 强奸乱伦免费网站| 97人肏| 久久超碰97中文字幕| 亚洲drav色图| 久久久久久69国产一区二区 | 97网址97| 日本操逼aaaaa| 日韩 欧美 另类 人妻| 九九色婷婷| 免費人妻夜夜爽天天爽爽一区| 久久久精品中文字幕麻豆| 色综合91好| 亚洲中文国际强奸字幕| 日日A∨| JuliaAnn丝袜熟女系列| 在线综合色| 久久久精品日本一道| 亚洲人久久久网| 色欧洲| 久操视频资源站公开| 亚码激情| 蜜臀Av一区二区三区| xxxx网站亚洲精品| 亚洲综合888| 天天欧美| 国产免费久久久久| 大香蕉青青9| 操操逼视频| 天无日色综合| 视频一区二区免费在线| 日韩成人色图| 又粗又长又大国产不卡| 亚洲丝袜二区| 日本熟妇人妻一区二区三区| 婷婷伊人綜合中文字幕小说| 91老熟女91老女人| 女人高潮大叫一级毛片| 国产精品夜夜夜| 久久国产性爱| 韩国国产欧美情侣视频在线| 人人做,人人操,人人摸| 免费看污网站| 影音先锋每日最新资源在线观看| 亚洲另类久操网| 熟女91网站| 正在播放:深夜激情大战,自带黑丝袜全力输出骚穴 | 亚洲第一精品在线视频| 色综合91好| 色五月激情网| 亚洲在线91| 99这里有精品视频| 丝袜亚洲综合| 亚洲综合99999| 超碰在线人妻中文字幕| 乱老熟女一区二区三区| 97摸视频| a片偷拍视频| 精品国产99| 最好看的中文字幕在线2018| 99热国产精品| 巨爆乳肉感一区二区三区竹菊影视 | 日日骚网站| 91蜜桃婷婷狠狠久久综合9色| 中出91视频| 99热9| 国产后入| 激情四射五月天| 亚洲欧美日韩精品久久久一区二区| 啊啊啊啊好疼视频| 91久精品| 综合久久久久久久综合网| 国产亚热在线久久| 色哟哟-国产专区| 涩涩这里只有精品视频| 久久69| 美欧老女人97| 亚洲国产日韩欧美熟妇在线| 蜜臀无码视频在线观看| 色欧洲97| 久久国产精品,久久国产| 高清无码久操视频| 熟妇一区,二区,三区。| 日本高清电影欧美色图| 在线岛| www久久精品| 91人妻爽爽人人做人人澡| 婷婷伊人五月| 亚洲激情在线| 91亚洲丝袜| 日本高清电影欧美色图| 一区操逼日比视频| 一区二区三区不卡视频| 玖玖资源视频一区二区三区| WWW美腿丝袜香蕉中文| 国产成人资源| 在线不卡视频| 午夜精品探花| 黄视频免费| 日韩欧视频| 欧美综合91| 日韩精品第3页| 992这里有精品| 欧美激情另类一区二区| 欧美黄色片在线播放| 亚洲自拍小说| 激情欧美97| 青青草五月份天| 影音先锋一区二区在线资源| 99国产精品在线观看| 亚洲黄网在哪免费看| 人人性爱视频免费| 综合97| 玖玖超碰熟| 欧美亚洲20p| 激情丁香五月婷婷| 曰韩成人免费视频| 亚洲一区二区久久久久| 强奸乱伦大香蕉| 国产精品不卡高清在线观看| 日本熟妇浓毛hdsex| 国产91美女视频| 舔舔啊| 久9爱经典视频| 欧美中字二区| 欧美91丝袜| 中文字幕天天操| 美女人妻色网站| 无码9区| 五月综合激情网| 色色激情五月天| 国产无套粉嫩白浆在| 国产乱色国产精品免费视| 国产精品懂色tv影视免费观看| 久久免费9| 亚洲欧美日韩不卡人妻| av天堂电影网| 亲子敌伦对白在线播放| A级国产欧美激情在线| 久久久久久久久999| 青草精品视频日本久久久久网站在线| 成人线上超碰| xxxx网站亚洲精品| 久久久久久国产无码精品| 亚洲一欧洲中文字幕在线| 乱伦图一区| 国产精品宅男免费| 九九色热| 高树玛利亚无码流出| 欧美熟妇乱码在线一区| 97热视频在线观看| 超碰色综合| 亚洲巨爆乳一区二区三区四季网| 日韩性爱1级片视频| 制度丝袜99| 操逼网站地址| 啊啊啊好湿国产一二| 日韩精品9999| 久久精品无码熟妇一区二区三区视频导航 | 免看60秒涩涩视频| 天堂综合网| 乱伦一二三| 色综合av男人天堂| 吻戏激情性巴克| 亚洲狼狼干综合1| 夜夜嗨绯色| 日韩欧美蜜桃精品久久中文字幕久久| 日韩大香蕉AV影片| 日韩极品无码B| 一区二区三区 日韩欧美| 久久性视频| 国产精品久久久亚洲一区| 一个人在线看的黄色电影网站| 一区二区三区成人| 欧美精品庄| A级毛片在线看免费| 久久精品国产亚洲AV高级北京| 激情色播| 正宗无毛一线天嫩逼| 亚洲视频中文一区| 日韩在线观看中文字幕视频| 嫩草伊人久久精品| V A在线| 伊人黄色视频免费观看| 亚洲情色五月天| 老熟妇一区二区三区啪啪| 999久久久国产精品| 在线岛国新天堂8| 2010男人的天堂| 欧美综合 站| 精品福利| 91久久久久免| 久久香蕉国产线看观看亚洲女人 | 色噜噜综合网| 免费成人在线熟妇网| 好吊色青靑草| 久操大香蕉手机视频在线看| 久久后入制服| 亚洲国产高清福利视频| 久久综合女优| 亚洲本色精品一区二区久久| 婷婷午夜| 青青操日韩| 亚洲蜜乳av| 久久久久久久久久久97| 97在线免费| 狠狠操狠狠爱| 超碰在线免费一区二区三区| 久久草在线综合视频| 麻豆 亚洲 97| 亚洲图片色图欧美另类| wwe 天天干.com| 手机看片91人妻| 国产精品一二三免费网站| 91天天综合在线观看| 人人 操人人 操人人| 97精品国产97久久久久久户外免费| 999国产精品999久久久久久| 长长久久88视频| 日韩欧美麻豆 | 欧美视频激情久久久久久| 天天影视色香欲综合网小说| 九九热九九热| 久久久精品中文字幕爱豆| 欧美日本久久精品一区| 99re免费视频精品全部| 日韩久久超碰色| 五月丁香黄色网| 成人综合网 欧美| 欧美十八禁视频| 日韩少妇丰满亚洲| 日韩av不卡在线观看| 久久色AV线| 嫩草影院性色| 传媒在线观看一区二区三区| 夜夜爽33333| 大JI巴好深好爽又大又粗视频| 欧美超碰9798| 久久亚州精品成人Av无| 校园春色亚洲无码| 99碰碰| 欧美色另类| 老鸭窝亚洲毛片| 亚洲婷婷综合网| 亚洲第91页 | 国产久久一区二区午夜| 欧美性爱第一区| 天堂精品| 另类图片亚洲加勒比另类图片亚洲加勒比另类图片亚洲加勒比 | 中文字幕高清精品一区| 东京热99999| 中国亚洲呦女专区| 热思思免费视频| 蜜桃久久久久久久久久久久| 亚欧国产无码精品在线| 99久久久久久亚洲精品不卡| 日本道人妻久久久在线不卡色视频| 女优视频第10页| 少妇与黑人高潮在线| 自怕偷自怕亚洲精品| 另类 日韩 熟女| 韩国女主播青草福利视频| 午夜福利 成人 91| 人妻中文字幕精品无码 | av在线不卡一区二区三区| 亚洲国产福利视频| 爱射综合| 日韩性爱网址| 国产乱色国产精品免费视| 超碰精品97| 日产中文字幕2020| 天天日天天色| 18禁超污无遮挡无码免费网| 这里只有精品视频在线| 操操逼视频| 国内一级精品| 99在线精品观看视频中文| 老熟妇综合| 天天弄天天操| 国产一区二区三区影片| 美国aaaaa一级黄片| 国产偷人伦激情在线观看| 人妻五十路在线| 色哟哟-国产专区| 免费一级视频特黄色大片| 1769国内精品视频| 人妻久久一区二区三区| asc国产精品| 欧美亚洲日韩16色| 91日日| 精品久久在线区一区| 中文字幕日本久久| 99久久久er直播网址| 亚洲性天堂| 色亚州人久干视频在线观看免费版| 91扒丝袜综合在线| 欧美久久草熟女| AV九九| 秋霞一级视频在线观看免费| 亚洲导航深夜福利| 国产精品国产精品国产| 久久精品99久久久久久| 亚洲美女 晚间男人天堂| 国产美脚女优尤物在线观看| 爱我干综合| 333kkkk·亚洲com久久| 国产一级作爱毛片| 艹少妇网站| 久久久久久人妻一区精品色欧美| 精品成人无码| 少妇3P性爱自拍| A级毛片在线看免费| 亚洲欧美成人网站AAA| 欧美牲| 色姑娘综合网| 97无码视频在线播放| 人妻精品视频一区二区三区| 国产中出内射一区二区| 秋霞成人做爱| 8050午夜少妇无码| 99在线免费观看| 五月天偷拍| 天综合网| 99www.bibizy香蕉资源国产一区二区三区高清 | 熟妇人妻一二三区免费| 国语精品对白| 亚洲成人性爱网站在线播放| 69精品久久久久中文字幕| 免费啪啪啪网站18岁| 国产精品国产拍高清AV| 丝袜性亚洲| 亚洲国内精品成人不卡| 天天狂操夜夜狂日| 中文字幕日韩电影人妻| 97超级欧美| 国产肏屁眼视频| 亚洲一区制服诱惑| 久久国产乱子伦精品免费女,网站| 蜜臀一区二区三区亚洲最新章节在线观看 - 高清蜜臀一区二区三区亚洲全集播放 | 日韩欧美中文| 亚洲午夜免费狠狠干| 亚洲国产一区二区三区在线| 久久久久久裸体| 日本媚薬中文字幕在线| 天天日天天搞天天干| 亚洲精品亚洲人成在线麻豆| 淫妻综合网| 大奶尤物鲍汁淫荡欧美视频粉嫩夜夜骚| 欧美91精彩| 美女黄色91| 激情小说图片亚洲首页| 探花激情视频| 西西美女视频网| 亚洲丨在线| 性暴力欧美猛交在线直播| 久久久97| 亚洲图片 激情小说| 淫淫综合网| ..日韩av毛片精品久久久| 久久久久久人妻| 青春草A| 台湾佬大香蕉| 凹凸视频特色日本特黄| 日本黄色裸日本黄色裸体 | 久久久精品国产亚洲AV无码| 97色视频在线| aaa亚无码专区| 美女被艹尤物视频| 曰本特级特黄特色黄色A级网站高清在线免费看 | 精品国产乱子伦一区二区三区,精品一| 日韩偷拍一区二区三区| 开心五月婷婷| 熟妇一区,二区,三区。| 日本一区二区做爱的视频| 亚洲熟女综合| 国产捆绑一区| 天美传媒国产原创中文字幕亚洲欧美另类| 日韩欧美天堂| 日本视频在线观看污污污| 国内黄色精品| CCYY草草影院地址入口| 日韩伦理久 久久 清纯| 亚洲天堂男人的天堂| 亚洲欧美精品福利在线| 亚洲自拍青操视频| 黄片免费久久久久久久| 区二区亚洲婷| 26uuu性| 精品亚州18| 国产一区免费午夜视频| 亚洲91网站| 操操吧亚洲乱伦视频| 国产婷婷一区| 强奸国产精品视频| 久久大黄片| 婷婷五月色| 粉嫩av一区二区三区天美传媒| 亚洲无码久久久久久久| 一区二三区四区视频大全套| 无码精品一区二区三区潘金莲| 丝袜翘臀后入欧美校园亚洲自拍另类小说一区中文字幕少妇诱惑 | 亚洲淫色网中文| 少妇无码av专区线| 伊人久久亚洲色欲综合网站 | 亚洲自拍欧美色综合| 国产女乱淫真高清免费视频| 妇女乱色二区| 开心五月天激情网| 日本影视久久免费| AV丝袜少妇| 精品人妻一区二区视频| 蜜桃臀AV在线| 亚洲 日韩 欧美 国产综合体| 五十路三区在线| 亚洲天堂色图| 黄色片一区二区三区四区五区| 天堂射| 不卡啪啪视频| 99999精品| 一区二区三区蜜桃成人撸久久东京热| 蜜乳AV.COM| 少妇精品久久久八区九区| 成人日韩欧美| 操婢日韩| 久久线上视频免费看| 日韩pv中文| 人人贴人人摸| 91色宗合| 久久久九九九九| 韩国黄色片精品久久久| 一区在线精品中文字幕| 色偷偷男人的天堂麻豆| 吻戏激情性巴克| 韩国手机不卡无码三级视频| 啊啊啊 在线| 特级大荫道BBwBBwBBW| 亚洲天堂AV在线播放| 色欲天香天天综合网-成年人三级片网站-欧美乱妇狂野-日韩国产专区-久久久久久 | 欧美特大AA级黄片| 麻豆色约约| 影音综合网| 亚洲女毛多水多21P| 超碰99re| 色哟哟AV| 久久精品免视看国产成人﹣蜜臀av一区. 久久精品免视看国产成人,蜜臀av一区 | 玖玖综合.com| 午夜无码精品免费看性色| 中文乱码字幕观看| 国产精品一二三| 日韩99神马视频播放| 亚洲中文字幕av| 不卡av在线中文字幕| 美女高潮国产高清| 91亚洲欧美综合高清在线| 婷婷三区| 五月天亚洲网| 国产亚卅97| 夜夜爽33333| 91强奸乱轮| 欧美成人A√在线一区二区| 东京热毛片调教| 美女黑人91神马| 青青操97| 久久超碰爱| 九热视频| 自偷自拍的亚洲视频| 久久五十路熟女人妻| 张柏芝国产一区在线观看| 97超碰伊人| 十八禁电影伊人网| 韩国国产欧美情侣视频在线| 午夜欧美J进J出白浆流出久久久| 91婷婷伊人狠人| 热久久这里只有精品| 欧美专区日本专区| 男人高清无码一区二区| 人人操人人插人www| 亚洲97成人在线观看| 久久久精品网站| 校园春色五月天| 精品无码久久| 91狠狠综合久久| 超碰诱惑| 欧美AB在线| 亚洲超碰97| 久久精品人妻一区| 亚洲视频中文一区| 国产乱伦性爱区| 亚洲乱色熟女一区| 色黄污美女啪啪啪免费网站| 中国一级操逼视频| 97人人操人人摸人人爱| 一区三区啪啪| 97人人操人人干| 992这里有精品| 日本人妻一区二区| 91久久18禁| 神马久久中文字幕| 加勒比人妻综合| 亚洲在钱| 九热中文字幕| 老外又粗又长一晚做五次| 一二三四视频中文字幕在线看| 亚洲AV无码翔田千里网站| 国产不卡免费在线视频| 91精品大奶人妻| 猛交交| 国产性刺激| 色综合99999| 天天日天天干天天摸天天操| 香蕉视频欧美一卡二卡| 亚洲精品乱码线路中文字幕 | 亚洲 图片 欧美 色图| 麻豆一区二区三区精品| 国产黑白丝在线| 91啪啪| 人人看人人爰人人操| 亚洲免费人妻在| 日韩AV电影网站| 9久久美女首页| 欧美草草高清日韩视频| 成人午夜高潮av猛片| 超碰成人最新最好看| www.天天干| 欧美青青视频| 熟女人妻一区二区三区| 精品一区二区综合熟妇| 日本久操视频| 色综合 加勒比| 女性喷水高潮在线观看| 澳门特级毛片免费观看| 亚射在线| 91精品人妻一区二区三区蜜臀| 8x福利精品第一福利视频导航| 亚洲天堂 视频你懂的| 亚洲国产剧情少妇激情| 校园春色美腿丝袜| 日韩免费在线视频观看| 伊人天堂在线| 九九九九九九精品| 一牛影视成人片免费| 天美传媒国产原创中文字幕亚洲欧美另类 | 蜜奶av| 啊啊啊久久| 色欲蜜臀AV| 第二页中文字幕| 九九九九精品视频| 日韩乱伦视频| 日本好吊色视频| 国产一区二区成人av在线播放| 91狠狠综合久久久久久| 久久九九精品一区二区| 少妇无码av专区线| 91网亚洲| 久久精品国产亚洲AV先锋| 我要看免费韩日黄片| 99黄页网站| 亚洲日本激情| 久久最新视频免费观看| 测评在线观看AV| 囯产精品一区二区三区线|亚洲人成无码网WWW动漫|国产精品免费一级... | 超碰在线91| 91一起操| 后入人妻无码| 999国产精品999| 色婷婷一区二区三区久久午夜| 两女互慰AV高潮喷水在线观看| 99超碰色| 美女被啪到深处抽搐视频| 精品超碰中文在线| 久这精品中文在线观看视频| 99热色精品| 大香蕉日韩| 天天综合色| 97Ai亚洲| 97免费在线视频在线观看| 2017天天拍大香蕉| 97色插| 久久久久久国产成人| 黄色高清久久无码依人| 青青免费在线视频一区| 人人妻人人色| 成人三一级一片aaa| 欧美第一页| 日韩性爱播放| 日本女人久久久| 啊啊啊啊啊啊在线看| 色色毛片| 欧美男人亚洲天堂| 日本高清一区二区在线| 一本大道久| www.婷婷六月天| 91亚洲色图| 欧美日韩一干二干| 在线观看AV片| 青女偷拍网| 久无码| www..com操老师| 中文字幕第7页| 最新欧美色网| 日韩精品在线视频在线观看| 手机av亚洲丝袜美腿日韩第一页二页| 中文字幕日本久久| 欧美亚洲图片| 玖玖爱一区在线| 插欧洲美女欧美精品| 97碰久久| 天美传媒Av在线| 717影院理论午夜伦八戒| 东京热大香蕉| 亚洲天天影视色综合| 五月丁香啪啪啪| AA级电影三区| 亚洲深夜福利| 精品无码一二三四区| www激情| 性色av大全| 97在线播放| 国产SV一线| 久操九九九九九九九九九九九九九九九九九九九九九九九九九九九九 | 婷婷色色五月天福利| 青青操视频在线| 亚洲.欧美.丝袜.中文.综合| 黄色AAAAA欧美| 97天天操| 青青草导航在线视频| 毛片17S| 九久9精品| 日韩免费在线视频观看| 好爽视频在线观看视频 | 日韩精品在线观看观看| 亚州综合色| 少妇高潮喷水无套久久久久久| 97国产精品国| 中文字幕一区二区三区视频播放| 日韩性爱免费观看视频| 国产精品视频在线观看| 青操影院| 热久日综合| 欧洲Au麻豆| 3571色综合一区二区二区| 女人喷水视频在线观看| 国产最火爆久久国产网站网站| 一二三区精品视频| 中文字幕午夜精品久久久| 大香蕉宅男伊人| 素人美腿视频网站| 亚洲色图大香| 这里只有精品视频在线| 亚洲欧洲日韩国产自在线| 国产探花日韩援交| 91啦人妻| 91人妻人人澡人人爽人人精品| 欧美精品一二三| 丝袜美腿操av| 少妇人妻在线| 欧美线天码中字| 99re在线视频| 亚洲男人综合网| 人人妻人人色| 99热 按摩 日韩| 日韩精品99久久久久久中文字幕 | 亚洲天天综合| 女人天堂av在线播放| 91美女视频在线观看| 中文字幕精品码亚洲| 久久有码视频| 伊人超碰97| 99无码| 家庭乱伦麻豆| 日韩免费高清大片在线| 92性色国产午夜福利在线661| 性色AV蜜色av色欲av| 青娱乐淫乱1314| 国产辣妈在线视频福利| 岛国片在线播放| 无套内射人妻在线播放| 在线观看AV片| 欧美日韩中文亚洲v在线综合| 青娱乐久久艹| 久久婷婷伊人| 加勒比在线视频| 亚洲第一页欧美| 夜夜操一区二区| 亚洲亚洲亚洲天堂天堂| 上床啊啊啊| 91在线免费精品视频| 韩国手机不卡无码三级视频| 亚乱色| 99热91| 亚洲综合影视| 91国产丝袜美女| 亚洲男人天堂网站| 人人么人人操| 国产精品999zyz| 337p大胆噜噜噜噜噜91Av| 亚洲综合97中文网| 欲香欲色天天天综合和网| 久欲AV| 欧美亚洲91| 二男一女成人A片| 啊视频在线| 五月天色图| 99re在线视频这里只有精品| 屁股久久久久久| 国产亚洲精品美女久久久久久2021| 无码日韩网站| av情色影音| 男人的天堂kva| 人人看黄色视频| 婷婷色香| 草B在线| 囯戸精品高潮呻吟旡码| 91超碰人人操| 东北女人| 亚洲开心网| 欧日a| 东京热一区二区三区四区五区六区| 日本天天干天天日一区| 懂色aV一区二区天美传媒| 狠狠操夜夜| 中文字幕一区二区三区人妻少妇在线| 美国三级日本三级久久99| 国产午夜精品理论片a大结局| 久久99午夜精品一区人妻| 一区二区久久天天干狠狠| 亚洲情色综合网| 免费av高清无码| 久久久爆乳翘臀一线天伦理视频| 成人欧美日超碰| 韩国免费播放一级毛片| 亚洲成人综合在线| 99热18这里只有精品| 天天看天天干| oumeisetu综合| 天干天干天干天天做| 日韩性爱1级片视频| 91老司机在线视频免费观看| 91色欧美| 免费看日产一区二区三区| 性老妇一区二区三区| 高清孕妇孕交| 蜜桃久久综合视频| 大鸡巴久久| 日韩黄色成人性爱| 黄色一区三区| 伦伦成年午夜免费视频| 亚洲精品欧洲精品| 精品人妻中文字幕高清| 91 刺激在线| 久久有码视频| 成人av动漫在线观看| 九9热伊人| xxxx网站亚洲精品| 国产精品suv一区| 精品久久无码午夜福利| 国产精品久久发布| 亚洲天堂一区| 97视频观看| 久久久久久97| 麻豆蜜桃视频在线观看| 福利视频合集| www.操| 天天看精品动漫视频一区| 校园春色亚洲欧洲| 黄人人操人人操| 综合在线导航一区| 中文字幕三四五区| 9/A片 | 亚洲成人久久美女| 综合五月婷婷亚洲一区| 午夜激情成人在线观看| 日本淫乱女一区二区三区视频| 91成人无码| …亚洲黄色厕厕女女在线播…| 怡红院成人视频| 久久国产乱子伦精品免费女,网站| 国内毛片四区| 精品视频一区二区| 美日韩男女操屄视频| 国产精品亚洲无码| 美女国产一区二区久久| 久久欧美性爱视频| 艳美熟妇先锋一二三区| 99.色网| 狠狠做深爱婷婷久久二区| 久久中文字幕女同性恋一区| 久久综合97| 麻豆国产97在线| 丝袜熟女一区二区三区| 9 9精品一区二区三区| 手机不卡视频不卡在线一二三区| 精品久久九| 久久啊啊| 亚洲 国产 精品一区| 亚洲 日韩 欧美 国产综合体| 国产精品suv一区| 欧美情色亚洲| 大色综合网| 久9久9精品| 男人在线天堂| 亚洲午夜av| 中国的操老妇女| 九九综合九九综合| www久久久| 91综合天天看| 亚洲人在线| 伊人视频| 奸色色 男人天堂 天天射| 精品成人亚洲午夜电影| 尤物网站91| 一二区在线观看视频| 夜夜综合| 亚洲第一色页夜| 操少妇很爽av| 亚州色交| 国产理论视频在线播放| 啊嗯嗯啊好大好爽| 久久久国产亚洲精品系列| 精品美女久久一二三| 手机在线播放国产福利| 五月开心久久AV官网| 久草网站免费在线观看| 粉嫩小泬久久久一区二区| av天堂精品久久| 精品二区三四区五电影 | 国产乱婷婷精品二区三区| 中文字幕人成乱码熟女香港| 在线观看亚洲专区| 国产精品一区二区三区在线密挑| 亚洲人妻色图| 亚洲精品蜜桃久久久一区二区三区| 综合亚洲欧美| 亚洲高清在线| 东京热,男人的天堂| 黄色激情电影在线观看| 超碰97网址| 亚洲精品97p| 欧美高清在线| 小情侣高清国产在线视频| 日韩淫色网| 五月天婷婷基地| 亚洲中文字幕熟女| 精品久久久久久久久久久久| 日本成人电影资源网| 欧美se综合| 丁香婷婷激情五月天无毒不卡| 丰满人妻无码一区二区三区| 清纯唯美综合亚洲| 欧美精品丝袜久久久中文字幕| 无码人妻丰满热妇又大又粗| 亚洲激情在线| 国产精品久久久久久久免牛肉蒲团 | 五月激情在线| 日本熟女免费視颖| 香蕉视频精品亚洲一区二区三区在线播| 女同性恋一区二区三区精品视频| 国产 亚洲 丝袜 制服| 中国AAAAAA黄色片| 欧美日韩人妻精品系列一区二区三区| 一区二区三区四区五区高清无码永久视频 | 午夜黄色免费在线观看| 日韩欧美日韩| 少妇三p| 日日摸日日弄日日拍| 天堂伊人久久| 人妻内射一区二区在线视频| 岛国小电影| 精品夜夜澡人妻无码| 色噜噜综合在线| 思思热在线观看| 天天舔天天 | 国产少妇与亚洲av| 五月丁香久久| 亚洲天堂色图| 亚洲AV高潮| 91中文精品日韩欧美在线| 人妻在线臀日韩| 330Dv国产女人终合视频极品人与兽| 91丨国产丨白浆| 国产男女无套97| 亚洲人码13| 快播久久人人aV| 中文字幕一区二区视频在线观看| 91爱网| 欧 美 自 拍 偷 拍| 综合免费无码中文| 九九色逼| 欧美在线色图| 久久久性少妇| 男人的天堂2019| 黄色人人| 熟妇熟女视频一区二区三区| 炮色五月| 久久久草草精品| V A在线| 男人a天堂手机在线版| 亚洲激情久久| www. 男人天堂成人在线| 99热这里都是精品| 日韩人妻一二三区视频| 99热精品在线| 久艹99| 久久性爱精品一区| 亚洲综合另类| 中日韩久久久免费看| 91精品女厕偷拍视频| 亚洲伊人a线观看视频| 日韩视频小说在线观看| 欧美日韩香蕉| 欧美组图日韩亚洲中文字幕| 久久久专区| 色综合久| 在线A日本| 日韩啪啪视频| 婷婷九月国产| 中文字幕片| 综合久久99| 黄色AAAAAAAAAAA大片| 亚洲色图在线视频| 亚洲毛片久久| aaa一级黄片| 国产97亚洲| 亚洲美女精品| 乳欲人妻办公室奶水| 国产精品色哟哟| 亚洲免费成人在线高清无码视频 | 久久婷婷色综合一区二区三区| 亚洲无码日韩电影| 91原创在线观看| 影音先锋少妇| 97精品在线视频| 玖色AV| 天美一区在线| 中文操逼字幕| 99精品久久| 高清不卡 中文 人妻| 亚洲**2021在线观看| 日本大片日本一区二区免费高清 | 亚洲在线网站| 成人欧美一区二区三区黑人一| 国产视频大全| 国产中文字幕在线点播| 亚洲日韩AV视色| 国产精品白丝AV| 日日操丁香五月天| 99色婷婷中文字幕乱色| 在线午夜成人无码视频| 夂久色| 国色综合天| 俺去也婷婷| 免费视频观看60秒| 精品一区二区亚洲国产| 97国产综合欧美| 国产区91柔拿会所技师| 亚洲国产精品久久久男人的天堂| 日韩综合无码一区久久92| 日本 欧美 亚中文字幕| 婷婷国产精品一区二区| 色情五月丁香| 91免费看中出视频| 亚洲啪啪性视频| 青青草色AV| 99久在线精品99re8| 久久久78| 激情五月天婷婷| 欧美综合网A| 久久,精品一二三| 野狼福利社区| 久久久艹艹艹| 肏逼视频日本| 91国产大片| 亚洲人妻在线一区| 久久99深爱久久99精品| 国产高清精品福利| 九色 蝌蚪 熟女自| 噜噜吧,噜噜色,噜噜| 欧美日韩欧美| 黄色大片一区二区密桃丝袜| 2021国产成人精品久久| 宗合情欲网| 秋霞久久亚洲精品成人| 国模久久在线| 久久99热这里只频精品6学生| 天天干嫩逼网| 一区麻豆 高清中文字幕| 超碰无码加勒比| 亚州图片第一页| 4399成人黄A片| 超碰午夜| 日本熟妇色熟妇在线视频播放| 人人摸人人干人人拍97| 992大香蕉| 日本三级日本三级三级人妇四虎| 最新亚洲人成网站在线影院| 久久视频,这里只有精品 | 成人午夜无码视频| 91综合中文字幕| 麻豆伊人网| 高清在线偷拍自拍视频| 欧美激情综合| 久久久国产精品亚洲精品| 婷婷色播婷婷| 国产婷婷综合在线观看| 大香蕉92| 97干在线看| 美国一区二区免费视频| 亚洲一二三四区| 欧美影音在线| 粉嫩国产精品久久粉嫩| 美国人人操人人操| 97亚洲中文| 日日做夜狠狠爱欧美黑人| 亚洲综合五月天| 不卡av在线中文字幕| 東南亚性呦成人伦理资源在线视频| 欧美熟妇精品黑人巨大一二三区| 亚洲AV无码黄色强奸| 日本不卡五区| 日日干夜夜骑| 成人无码专区精品视频| 国产女生在线| 黑人美精品 A片| 熟女熟妇一区二区三四区| 国产又大又粗又色生活片亚洲国产精品成人久久久综合免费 | 18禁的网站在线| 色婷网| 青娱乐老司机视频| 亚洲综合嫩| yy少妇精品久久| 亚洲熟妇图片| 91久久99久久91熟女精品| 岛国福利在线精品播放| 中文字幕一区二区无码成人| 丰满精品人妻少妇久久字幕| 亚洲av夫妻操穴网| 日本高清一区二区在线| 中文字幕日韩人妻视频| 九九草| 婷婷8月天青娱乐| 欧美日韩国产人人| 亚洲综合另类欧美久久久| 97干在线| 爆操无码| 欧美日韩操逼动图| 中国AV美女| 国产成人在线观看网址| 人妻熟女一区二区在线视频| 制服丝袜第二页| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 高清不卡国产| 亚洲高潮少妇| 啪啪啪综合网| 日韩成人大片在线观看| 逼逼逼逼操操操操操操操操操午夜剧场| yaouchengrenav| 97精品视频| 久久久蜜桃臀无码视频| JuliaAnnXXX888| 全国男人天堂网| 亚洲午夜蜜臀| 9 1超碰九色| 亚洲欧美天| 噜噜噜噜天天狠狠| 亚洲一区中文字幕| 中文字幕国产| 黑人性暴力毛片| 精品日韩产品在线,日韩在线不卡视频,欧美日韩免费专区/久, | 国产亚洲人妻综合日韩 久久| 97干在线视频| 超碰在线看| 超碰久热| 欧美拳交在线播放| 天天透伊人| 人人爽夜夜操| 亚洲限制级| 欧美与日韩97| 超碰偷拍| 夜夜欧美 | 97任你吞精| 日本在线不卡一二区| 婷婷五月天成人| 伊人天堂在线| 久久av色| 色九九综合AV|