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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

javascript设计模式--命令模式

發(fā)布時間:2023/12/9 javascript 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascript设计模式--命令模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>命令模式</title> 5 <meta charset="utf-8"> 6 </head> 7 <body> 8 9 <script> 10 /** 11 * 命令模式 12 * 13 * 定義: 14 * 將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化,對請求排隊或記錄請求日志,以及支持可撤銷的操作。 15 * 16 * 本質(zhì): 17 * 封裝請求 18 * 19 * 命令模式是一種封裝方法調(diào)用的方式。命令模式與普通函數(shù)所有不同。它可以用來對方法調(diào)用進行參數(shù)化處理和傳送,經(jīng)這樣處理過的方法調(diào)用可以在任何需要的時候執(zhí)行。它也可以用來消除調(diào)用操作的對象和實現(xiàn)操作對象之間的耦合,這位各種具體的類的更換帶來了極大的靈活性。這種模式可以用在許多不同場合,不過它在創(chuàng)建用戶界面這一方面非常有用,特別是在需要不受限的(unlimited)取消(undo)操作的時候,它還可以用來替代回調(diào)函數(shù),因為它能夠提高在對象之間傳遞的操作的模塊化程度。 20 * 21 * 在命令模式中,會定義一個命令的接口,用來約束所有的命令對象,然后提供具體的命令實現(xiàn),每個命令實現(xiàn)對象是對客戶端某個請求的封裝,對應于機箱上的按鈕,一個機箱上可以有很多按鈕,也就相當于會有多個具體的命令實現(xiàn)對象。 22 * 在命令模式中,命令對象并不知道如何處理命令,會有相應的接收者對象來真正執(zhí)行命令。就像電腦的例子,機箱上的按鈕并不知道如何處理功能,而是把這個請求轉(zhuǎn)發(fā)給主板,由主辦來執(zhí)行真正的功能,這個主板就相當于命令模式的接收者。 23 * 在命令模式中,命令對象和接收者對象的關系,并不是與生俱來的,需要有一個裝配的過程,命令模式中的Client對象可以實現(xiàn)這樣的功能。這就相當于在電腦的例子中,有了機箱上的按鈕,也有了主板,還需要一個連接線把這個按鈕連接到主板上才行。 24 * 命令模式還會提供一個Invoker對象來持有命令對象。就像電腦的例子,機箱上會有多個按鈕,這個機箱就相當于命令模式的Invoker對象。這樣一來,命令模式的客戶端就可以通過Invoker來觸發(fā)并要求執(zhí)行相應的命令了,這也相當于真正的客戶是按下機箱上的按鈕來操作電腦一樣。 25 * 26 * 命令模式的關鍵 27 * 命令模式的關鍵之處就是把請求封裝成對象,也就是命令對象,并定義了統(tǒng)一的執(zhí)行操作的接口,這個命令對象可以被存儲,轉(zhuǎn)發(fā),記錄,處理,撤銷等,整個命令模式都是圍繞這個對象在進行。 28 * 29 * 命令模式的組裝和調(diào)用 30 * 在命令模式中經(jīng)常會有一個命令的組裝者,用它來維護命令的“虛”實現(xiàn)和真實實現(xiàn)之間的關系。如果是超級智能的命令,也就是說命令對象自己完全實現(xiàn)好了,不需要接收者,那就是命令模式的退化,不需要接受者,自然也不需要組裝者了。 31 * 而真正的用戶就是具體化請求的內(nèi)容,然后提交請求進行觸發(fā)就可以了。真正的用戶會通過Invoker來觸發(fā)命令。 32 * 在實際開發(fā)過程中,Client和Invoker可以融合在一起,由客戶在使用命令模式的時候,先進行命令對象和接收者的組裝,組裝完成后,就可以調(diào)用命令執(zhí)行請求。 33 * 34 * 命令模式的接收者 35 * 接收者可以是任意的類,對它沒有什么特殊要求,這個對象知道如何真正執(zhí)行命令的操作,執(zhí)行時是從Command的實現(xiàn)類里面轉(zhuǎn)調(diào)過來。 36 * 一個接收者對象可以處理多個命令,接收者和命令之間沒有約定的對應關系。接收者提供的方法個數(shù),名稱,功能和命令中的可以不一樣,只要能夠通過調(diào)用接收者的方法來實現(xiàn)命令對應的功能就可以了。 37 * 38 * 命令模式的調(diào)用順序 39 * 使用命令模式的過程分成兩個階段,一個階段是組裝對象和接收者對象的過程,另外一個階段是觸發(fā)調(diào)用Invoker,來讓命令真正的執(zhí)行。 40 * 組裝過程: 41 * 1.創(chuàng)建接收者對象。 42 * 2.創(chuàng)建命令對象,設置命令對象和接收者對象的關系。 43 * 3.創(chuàng)建Invoker對象。 44 * 4.把命令對象設置到Invoker中,讓Invoker持有命令對象。 45 * 執(zhí)行過程: 46 * 1.調(diào)用Invoker的方法,觸發(fā)要求執(zhí)行命令。 47 * 2.要求持有的命令對象只能執(zhí)行功能。 48 * 3.要求持有的接收者真正實現(xiàn)功能。 49 * 50 */ 51 52 (function () { 53 // 示例代碼 54 55 /** 56 * 具體的命令實現(xiàn)對象 57 * @params {Object} receiver 持有相應的接收者對象 58 */ 59 function Command(receiver) { 60 this.receiver = receiver; 61 // 命令對象可以有自己的狀態(tài) 62 this.state = ''; 63 } 64 65 Command.prototype.execute = function () { 66 // 通常會轉(zhuǎn)調(diào)接收者對象的相應方法,讓接收者來真正執(zhí)行功能 67 this.receiver.action(); 68 }; 69 70 // 接收者對象 71 function Receiver() { 72 } 73 74 // 真正執(zhí)行命令相應地操作 75 Receiver.prototype.action = function () { 76 }; 77 78 /** 79 * 調(diào)用者 80 * 81 */ 82 function Invoker() { 83 } 84 85 /** 86 * @params {Object} command 持有命令對象 87 */ 88 Invoker.prototype.setCommand = function (command) { 89 this.command = command; 90 }; 91 // 要求命令執(zhí)行請求 92 Invoker.prototype.runCommand = function () { 93 this.command.execute(); 94 }; 95 96 new function Client() { 97 var receiver = new Receiver(); 98 var command = new Command(receiver); 99 var invoker = new Invoker(); 100 invoker.setCommand(command); 101 invoker.runCommand(); 102 }(); 103 }()); 104 105 /* 106 命令的結(jié)構(gòu) 107 108 最簡形式的命令對象是一個操作和用以調(diào)用這個操作的對象的結(jié)合體。所有的命令對象都有一個執(zhí)行操作(execute operation),其用途就是調(diào)用命令對象所綁定的操作。在大多數(shù)命令對象中,這個操作是一個名為execute或run的方法。使用同樣接口的所有命令對象都可以被同等對待,并且可以隨意互換,這是命令模式的魅力之一。 109 110 假設你想設計一個網(wǎng)頁,客戶可以在上面執(zhí)行一些與自己的賬戶相關的操作,比如啟用和停用某些廣告。因為不知道其中的具體廣告數(shù)量,所以你想設計一個盡可能靈活的用戶界面(UI)。為此你打算用命令模式來弱化按鈕之類的用戶界面元素與其操作之間的耦合。 111 */ 112 113 // 定義兩個類,分別用來封裝廣告的start方法和stop方法 114 // StopAd command class 115 var StopAd = function (adObject) { 116 this.ad = adObject; 117 }; 118 StopAd.prototype.execute = function () { 119 this.ad.stop(); 120 }; 121 122 // StartAd command class 123 var StartAd = function (adObject) { 124 this.ad = adObject; 125 }; 126 StartAd.prototype.execute = function () { 127 this.ad.start(); 128 }; 129 /* 130 現(xiàn)在有個兩個可用在用戶界面中的類,它們具有相同的接口。你不知道也不關心adObject的具體實現(xiàn)細節(jié),只要它實現(xiàn)了start和stop方法就行。借助于命令模式,可以實現(xiàn)用戶界面對象與廣告對象的隔離。 131 */ 132 133 /* 134 下面的代碼創(chuàng)建的用戶界面中,用戶名下的每個廣告都有兩個按鈕,分別用于啟動和停止廣告的輪播: 135 */ 136 // implementation code 137 var ads = getAds(); 138 for (var i = 0, len = ads.length; i < len; i++) { 139 // Create command objects for starting and stopping the ad 140 var startCommand = new StartAd(ads[i]); 141 var stopCommand = new StopAd(ads[i]); 142 143 // Create the UI elements that will execute the command on click 144 new UIButton('Start ' + ads[i].name, startCommand); 145 new UIButton('stop ' + ads[i].name, stopCommand); 146 } 147 /* 148 UIButton類的構(gòu)造函數(shù)有兩個參數(shù),一個是按鈕上的文字,另一個是命令對象。它會在網(wǎng)頁上生成一個按鈕,該按鈕被點擊時會執(zhí)行那個命令對象的execute方法。這個類也不需要知道所用命令對象的確切實現(xiàn)。因為所有命令對象都實現(xiàn)了execute方法,所以可以把任何一種命令對象提供給UIButton。這有助于創(chuàng)建高度模塊化和低耦合的用戶界面。 149 */ 150 151 /* 152 用閉包創(chuàng)建命令對象 153 154 還有另外一種辦法可以用來封裝函數(shù)。這種辦法不需要創(chuàng)建一個具有execute方法的對象,而是把想要執(zhí)行的方法包裝在閉包中。如果想要創(chuàng)建的命令對象像前例中那樣只有一個方法。那么這種辦法由其方便。現(xiàn)在你不再調(diào)用execute方法,因為那個命令可以作為函數(shù)直接執(zhí)行。這樣做還可以省卻作用域和this關鍵字的綁定的煩惱。 155 */ 156 157 // Command using closures 158 function makeSart(adObject) { 159 return function () { 160 adObject.start(); 161 }; 162 } 163 function makeStop(adObject) { 164 return function () { 165 adObject.stop(); 166 }; 167 } 168 169 // Implementation code 170 var startCommand = makeStart(ads[0]); 171 var stopCommand = makeStop(ads[0]); 172 173 startCommand(); 174 stopCommand(); 175 /* 176 不適用于需要多個命令方法的場合,比如后面要實現(xiàn)取消功能的示例 177 */ 178 179 /* 180 客戶,調(diào)用者和接收者 181 182 這個系統(tǒng)中有三個參與者:客戶(client),調(diào)用者(invoking object)和接收者(receiving object)。客戶負責實例化命令并將其交給調(diào)用者。在前面的例子中,for循環(huán)中的代碼就是客戶。它通常被包裝為一個對象,但也不是非這樣不可。調(diào)用者接過命令并將其保存下來。它會在某個時候調(diào)用該命令對象的execute方法,或者將其交給另一個潛在的調(diào)用者。前例中的調(diào)用者就是UIButton類創(chuàng)建的按鈕。用戶點擊它的時候,它就會調(diào)用命令對象的execute方法。接收者則是實際執(zhí)行操作的對象。調(diào)用者進行“commandObject.execute()”這種形式的調(diào)用時,它所調(diào)用的方法將轉(zhuǎn)而以“receiver.action()”這種形式調(diào)用恰當?shù)姆椒ā6邮照呔褪菑V告對象,它所能執(zhí)行的操作要么是start方法,要么是stop方法。 183 184 客戶創(chuàng)建命令,調(diào)用者執(zhí)行該命令,接收者在命令執(zhí)行時執(zhí)行相應操作。 185 所有使用命令模式的系統(tǒng)都有客戶和調(diào)用者,但不一定有接收者。 186 */ 187 188 // 在命令模式中使用接口 189 // If no exception is thrown, youcan safely invoke the 190 // execute operation 191 someCommand.execute(); 192 193 // 如果用必報來創(chuàng)建命令函數(shù),只需檢查是否為函數(shù)即可 194 if (typeof someCommand !== 'function') { 195 throw new Error('Command isn\'t a function'); 196 } 197 198 199 // 命令對象的類型 200 /* 201 簡單命令對象就是把現(xiàn)有接收者的操作(廣告對象的start和stop方法)與調(diào)用者(按鈕)綁定在一起。這類命令對象最簡單,其模塊程度也最高。它們與客戶,接收者和調(diào)用者之間只是松散地偶合在一起: 202 */ 203 // SimpleCommand, a loosely coupled, simple command class. 204 var SimpleCommand = function (receiver) { 205 this.receiver = receiver; 206 }; 207 SimpleCommand.prototype.execute = function () { 208 this.receiver.action(); 209 }; 210 211 /* 212 另一種則是那種封裝著一套復雜指令的命令對象。這種命令對象實際上沒有接受者,因為它自己提供了操作的具體實現(xiàn)。它并不把操作委托給接收者實現(xiàn),所有用于實現(xiàn)相關操作的代碼都包含在其內(nèi)部: 213 */ 214 // ComplexCommand, a tightly coupled, complex command class. 215 var ComplexCommand = function () { 216 this.logger = new Logger(); 217 this.xhrHandler = XhrManager.createXhrHandler(); 218 this.parameters = {}; 219 }; 220 ComplexCommand.prototype = { 221 setParameter: function (key, value) { 222 this.parameters[key] = value; 223 }, 224 execute: function () { 225 this.logger.log('Executing command'); 226 var postArray = []; 227 for (var key in this.parameters) { 228 if (this.parameters.hasOwnProperty(key)) { 229 postArray.push(key + '=' + this.parameters[key]); 230 } 231 } 232 var postString = postArray.join('&'); 233 this.xhrHandler.request( 234 'POST', 235 'script.php', 236 function () { 237 }, 238 postString 239 ); 240 } 241 }; 242 243 /* 244 有些命令對象不但封裝了接收者的操作,而且其execute方法中也具有一些實現(xiàn)代碼。這類命令對象是一個灰色地帶: 245 */ 246 // GreyAreaCommand, somewhere between simple and complex 247 var GreyAreaCommand = function (receiver) { 248 this.logger = new Logger(); 249 this.receiver = receiver; 250 }; 251 GreyAreaCommand.prototype.execute = function () { 252 this.logger.log('Executing command'); 253 this.receiver.prepareAction(); 254 this.receiver.action(); 255 }; 256 257 /* 258 簡單命令對象一般用來消除兩個對象(接受著和調(diào)用者)之間的耦合,而復雜命令對象則一般用來封裝不可分的或事務性的指令。 259 */ 260 261 // 實例: 菜單項 262 // 菜單組合對象 263 /* 264 接下來要實現(xiàn)的事Menubar,Menu和MenuItem類,作為一個整體,他們要能顯示所有可用操作,并且根據(jù)要求調(diào)用這些操作,Menubar和Menu都是組合對象類,而MenuItem則是葉類。Menubar類保存著所有Menu實例: 265 */ 266 // MenuBar class, a composite 267 var MenuBar = function () { 268 this.menus = {}; 269 this.element = document.createElement('ul'); 270 this.element.style.display = 'none'; 271 }; 272 MenuBar.prototype = { 273 add: function (menuObject) { 274 this.menus[menuObject.name] = menuObject; 275 this.element.appendChild(this.menus[menuObject.name].getElement()); 276 }, 277 remove: function (name) { 278 delete this.menus[name]; 279 }, 280 getChild: function (name) { 281 return this.menus[name]; 282 }, 283 getElement: function () { 284 return this.element; 285 }, 286 show: function () { 287 this.element.style.display = ''; 288 for (var name in this.menus) { 289 this.menus[name].show(); 290 } 291 } 292 }; 293 294 // Menu class, a composite 295 var Menu = function (name) { 296 this.name = name; 297 this.items = {}; 298 this.element = document.createElement('li'); 299 this.element.style.display = 'none'; 300 this.container = document.createElement('ul'); 301 this.element.appendChild(this.container); 302 }; 303 Menu.prototype = { 304 add: function (menuItemObject) { 305 this.items[menuItemObject.name] = menuItemObject; 306 this.container.appendChild(this.items[menuItemObject.name].getElement()); 307 }, 308 remove: function () { 309 delete this.items[name]; 310 }, 311 getChild: function (name) { 312 return this.items[name]; 313 }, 314 getElement: function () { 315 return this.element; 316 }, 317 show: function () { 318 this.element.style.display = ''; 319 for (var name in this.items) { 320 this.items[name].show(); 321 } 322 } 323 }; 324 325 // 調(diào)用者類 326 // MenuItem class, a leaf 327 var MenuItem = function (name, command) { 328 this.name = name; 329 this.element = document.createElement('li'); 330 this.element.style.display = 'none'; 331 this.anchor = document.createElement('a'); 332 this.anchor.href = '#'; 333 this.element.appendChild(this.anchor); 334 this.anchor.innerHTML = this.name; 335 336 addEvent(this.anchor, 'click', function (e) { 337 e = e || window.event; 338 if (typeof e.preventDefault === 'function') { 339 e.preventDefault(); 340 } else { 341 e.returnValue = false; 342 } 343 command.execute(); 344 }); 345 }; 346 MenuItem.prototype = { 347 add: function () { 348 }, 349 remove: function () { 350 }, 351 getChild: function () { 352 }, 353 getElement: function () { 354 return this.element; 355 }, 356 show: function () { 357 this.element.style.display = ''; 358 } 359 }; 360 361 // 命令類 362 // MenuCommand class, a command object 363 var MenuCommand = function (action) { 364 this.action = action; 365 }; 366 MenuCommand.prototype.execute = function () { 367 this.action.action(); 368 }; 369 370 371 // Receiver objects, instantiated from existing classes 372 var Test1 = function () { 373 console.log('test1'); 374 }; 375 Test1.prototype = { 376 action: function () { 377 console.log('this is test1 fn1'); 378 } 379 }; 380 var Test2 = function () { 381 console.log('test2'); 382 }; 383 Test2.prototype = { 384 action: function () { 385 console.log('this is test2 fn1'); 386 } 387 }; 388 var Test3 = function () { 389 console.log('test3'); 390 }; 391 var test1 = new Test1(); 392 var test2 = new Test2(); 393 var test3 = new Test3(); 394 395 // Create the menu bar 396 var appMenuBar = new MenuBar(); 397 398 // The File menu 399 var fileMenu = new Menu('File'); 400 401 var test1Command1 = new MenuCommand(test1); 402 403 fileMenu.add(new MenuItem('test1-1', test1Command1)); 404 405 appMenuBar.add(fileMenu); 406 407 var insertMenu = new Menu('Insert'); 408 var test2Command2 = new MenuCommand(test2); 409 insertMenu.add(new MenuItem('test2-1', test2Command2)); 410 411 appMenuBar.add(insertMenu); 412 413 document.body.appendChild(appMenuBar.getElement()); 414 appMenuBar.show(); 415 416 417 (function () { 418 // 補償式或者反操作式 419 420 // 取消操作和命令日志 421 422 // ReversibleCommand interface 423 var ReversibleCommand = new Interface('ReversibleCommand', ['execute', 'undo']); 424 425 // 接下來要做的是創(chuàng)建4個命令類, 426 // 它們分別用來向上下左右四個方向移動指針: 427 var MoveUp = function (cursor) { 428 this.cursor = cursor; 429 }; 430 MoveUp.prototype = { 431 execute: function () { 432 this.cursor.move(0, -10); 433 }, 434 undo: function () { 435 this.cursor.move(0, 10); 436 } 437 }; 438 439 var MoveDown = function (cursor) { 440 this.cursor = cursor; 441 }; 442 MoveDown.prototype = { 443 execute: function () { 444 this.cursor.move(0, 10); 445 }, 446 undo: function () { 447 this.cursor.move(0, -10); 448 } 449 }; 450 451 var MoveLeft = function (cursor) { 452 this.cursor = cursor; 453 }; 454 MoveLeft.prototype = { 455 execute: function () { 456 this.cursor.move(-10, 0); 457 }, 458 undo: function () { 459 this.cursor.move(10, 0); 460 } 461 }; 462 463 var MoveRight = function (cursor) { 464 this.cursor = cursor; 465 }; 466 MoveRight.prototype = { 467 execute: function () { 468 this.cursor.move(10, 0); 469 }, 470 undo: function () { 471 this.cursor.move(-10, 0); 472 } 473 }; 474 475 // 接收者,負責實現(xiàn)指針移動 476 // Cursor class 實現(xiàn)了命令類所要求的操作 477 var Cursor = function (width, height, parent) { 478 this.width = width; 479 this.height = height; 480 this.position = { 481 x: width / 2, 482 y: height / 2 483 }; 484 485 this.canvas = document.createElement('canvas'); 486 this.canvas.width = this.width; 487 this.canvas.height = this.height; 488 parent.appendChild(this.canvas); 489 490 this.ctx = this.canvas.getContext('2d'); 491 this.ctx.fillStyle = '#cc0000'; 492 this.move(0, 0); 493 }; 494 Cursor.prototype.move = function (x, y) { 495 this.position.x += x; 496 this.position.y += y; 497 498 this.ctx.clearRect(0, 0, this.width, this.height); 499 this.ctx.fillRect(this.position.x, this.position.y, 3, 3); 500 }; 501 502 // 下面這個裝飾者的作用就是在執(zhí)行一個命令之前先將其壓棧 503 // UndoDecorator class 504 var UndoDecorator = function (command, undoStack) { 505 this.command = command; 506 this.undoStack = undoStack; 507 }; 508 UndoDecorator.prototype = { 509 execute: function () { 510 this.undoStack.push(this.command); 511 this.command.execute(); 512 }, 513 undo: function () { 514 this.command.undo(); 515 } 516 }; 517 518 // 用戶界面類,負責生成必要的HTML元素,并且為其注冊click事件監(jiān)聽器, 519 // 這些監(jiān)聽器要么調(diào)用execute方法要么調(diào)用undo方法: 520 // CommandButton class 521 var CommandButton = function (label, command, parent) { 522 this.element = document.createElement('button'); 523 this.element.innerHTML = label; 524 parent.appendChild(this.element); 525 526 addEvent(this.element, 'click', function () { 527 command.execute(); 528 }); 529 }; 530 531 // UndoButton class 532 var UndoButton = function (label, parent, undoStack) { 533 this.element = document.createElement('button'); 534 this.element.innerHTML = label; 535 parent.appendChild(this.element); 536 537 addEvent(this.element, 'click', function () { 538 if (undoStack.length === 0) return; 539 var lastCommand = undoStack.pop(); 540 lastCommand.undo(); 541 }); 542 }; 543 /* 544 像UndoDecorator類一樣,UndoButton類的構(gòu)造函數(shù)也需要把命令棧作為參數(shù)傳入。這個棧其實就是一個數(shù)組。調(diào)用經(jīng)UndoDecorator對象裝飾過的命令對象的execute方法時這個命令對象會被壓入棧。為了執(zhí)行取消操作,取消按鈕會從命令棧中彈出最近的命令并調(diào)用其undo方法。這將逆轉(zhuǎn)剛執(zhí)行過的操作。 545 */ 546 547 // Implementation code 548 var body = document.body; 549 var cursor = new Cursor(400, 400, body); 550 var undoStack = []; 551 552 var upCommand = new UndoDecorator(new MoveUp(cursor), undoStack); 553 var downCommand = new UndoDecorator(new MoveDown(cursor), undoStack); 554 var leftCommand = new UndoDecorator(new MoveLeft(cursor), undoStack); 555 var rightCommand = new UndoDecorator(new MoveRight(cursor), undoStack); 556 557 var upButton = new CommandButton('Up', upCommand, body); 558 var downButton = new CommandButton('Down', downCommand, body); 559 var leftButton = new CommandButton('Left', leftCommand, body); 560 var rightButton = new CommandButton('Right', rightCommand, body); 561 var undoButton = new UndoButton('Undo', body, undoStack); 562 }()); 563 564 565 (function () { 566 // 使用命令日志實現(xiàn)不可逆操作的取消 567 /* 568 在畫布上畫線很容易,不過要取消這條線的繪制是不可能的。從一個點到另一個點的移動這種操作具有精確的對立操作,執(zhí)行后者的結(jié)果看起來就像前者被逆轉(zhuǎn)了一樣。但是對于從A到B畫一條線這種操作,從B到A再畫一條線是無法逆轉(zhuǎn)前一操作的,這只不過是在第一條線的上方又畫一條線而已。 569 570 取消這種操作的唯一辦法是清除狀態(tài),然后把之前執(zhí)行過的操作(不含最近那個)一次重做一遍。這很容易辦到,為此需要把所有執(zhí)行過的命令記錄在棧中。要想取消一個操作,需要做的就是從棧中彈出最近那個命令并棄之不用,然后清理畫布并從頭開始重新執(zhí)行記錄下來的所有命令。 571 */ 572 573 // Movement commands 574 var MoveUp = function (cursor) { 575 this.cursor = cursor; 576 }; 577 MoveUp.prototype = { 578 execute: function () { 579 this.cursor.move(0, -10); 580 } 581 }; 582 583 var MoveDown = function (cursor) { 584 this.cursor = cursor; 585 }; 586 MoveDown.prototype = { 587 execute: function () { 588 this.cursor.move(0, 10); 589 } 590 }; 591 592 var MoveLeft = function (cursor) { 593 this.cursor = cursor; 594 }; 595 MoveLeft.prototype = { 596 execute: function () { 597 this.cursor.move(-10, 0); 598 } 599 }; 600 601 var MoveRight = function (cursor) { 602 this.cursor = cursor; 603 }; 604 MoveRight.prototype = { 605 execute: function () { 606 this.cursor.move(10, 0); 607 } 608 }; 609 610 // Cursor class, with an internal command stack 611 var Cursor = function (width, height, parent) { 612 this.width = width; 613 this.height = height; 614 this.commandStack = []; 615 616 this.canvas = document.createElement('canvas'); 617 this.canvas.width = this.width; 618 this.canvas.height = this.height; 619 parent.appendChild(this.canvas); 620 621 this.ctx = this.canvas.getContext('2d'); 622 this.ctx.strokeStyle = '#cc0000'; 623 this.move(0, 0); 624 }; 625 Cursor.prototype = { 626 move: function (x, y) { 627 var that = this; 628 this.commandStack.push(function () { 629 that.lineTo(x, y); 630 }); 631 this.executeCommands(); 632 }, 633 lineTo: function (x, y) { 634 this.position.x += x; 635 this.position.y += y; 636 this.ctx.lineTo(this.position.x, this.position.y); 637 }, 638 executeCommands: function () { 639 this.position = { 640 x: this.width / 2, 641 y: this.height / 2 642 }; 643 this.ctx.clearRect(0, 0, this.width, this.height); 644 this.ctx.beginPath(); 645 this.ctx.moveTo(this.position.x, this.position.y); 646 for (var i = 0, len = this.commandStack.length; i < len; i++) { 647 this.commandStack[i](); 648 } 649 this.ctx.stroke(); 650 }, 651 undo: function () { 652 this.commandStack.pop(); 653 this.executeCommands(); 654 } 655 }; 656 657 // UndoButton class 658 var UndoButton = function (label, parent, cursor) { 659 this.element = document.createElement('button'); 660 this.element.innerHTML = label; 661 parent.appendChild(this.element); 662 addEvent(this.element, 'click', function () { 663 cursor.undo(); 664 }); 665 }; 666 // CommandButton class 667 var CommandButton = function (label, command, parent) { 668 this.element = document.createElement('button'); 669 this.element.innerHTML = label; 670 parent.appendChild(this.element); 671 672 addEvent(this.element, 'click', function () { 673 command.execute(); 674 }); 675 }; 676 677 var body = document.body; 678 var cursor = new Cursor(400, 400, body); 679 680 var upCommand = new MoveUp(cursor); 681 var downCommand = new MoveDown(cursor); 682 var leftCommand = new MoveLeft(cursor); 683 var rightCommand = new MoveRight(cursor); 684 685 var upButton = new CommandButton('Up', upCommand, body); 686 var downButton = new CommandButton('Down', downCommand, body); 687 var leftButton = new CommandButton('Left', leftCommand, body); 688 var rightButton = new CommandButton('Right', rightCommand, body); 689 var undoButton = new UndoButton('Undo', body, cursor); 690 }()); 691 692 (function () { 693 // 宏命令 694 /* 695 去飯店吃飯過程。 696 697 客戶: 只負責發(fā)出命令,就是點菜操作。 698 命令對象: 就是點的菜。 699 服務員: 知道真正的接收者是誰,同時持有菜單,當你點菜完畢,服務員就啟動命令執(zhí)行。 700 后廚, 涼菜部: 相當于接收者。 701 702 菜單命令包含多個命令對象 703 */ 704 705 // 坐熱菜的廚師 706 var HotCook = function () { 707 }; 708 HotCook.prototype = { 709 cook: function (name) { 710 console.log('本廚師正在做:' + name); 711 } 712 }; 713 714 // 做涼菜的廚師 715 var CoolCook = function () { 716 }; 717 CoolCook.prototype = { 718 cook: function (name) { 719 console.log('涼菜' + name + '已經(jīng)做好,本廚師正在裝盤。'); 720 } 721 } 722 723 // 定義了三道菜,每道菜是一個命令對象 724 725 var DuckCommand = function () { 726 this.cookApi = null; 727 }; 728 DuckCommand.prototype = { 729 constructor: DuckCommand, 730 setCookApi: function (cookApi) { 731 this.cookApi = cookApi; 732 }, 733 execute: function () { 734 this.cookApi.cook('北京烤鴨'); 735 } 736 }; 737 738 var ChopCommand = function () { 739 this.cookApi = null; 740 }; 741 ChopCommand.prototype = { 742 constructor: ChopCommand, 743 setCookApi: function (cookApi) { 744 this.cookApi = cookApi; 745 }, 746 execute: function () { 747 this.cookApi.cook('綠豆排骨煲'); 748 } 749 }; 750 751 var PorkCommand = function () { 752 this.cookApi = null; 753 }; 754 PorkCommand.prototype = { 755 constructor: PorkCommand, 756 setCookApi: function (cookApi) { 757 this.cookApi = cookApi; 758 }, 759 execute: function () { 760 this.cookApi.cook('蒜泥白肉'); 761 } 762 }; 763 764 // 菜單對象,宏命令對象 765 var MenuCommand = function () { 766 var col = []; 767 768 this.addCommand = function (cmd) { 769 col.push(cmd); 770 }; 771 772 this.execute = function () { 773 for (var i = 0 , len = col.length; i < len; i++) { 774 col[i].execute(); 775 } 776 }; 777 }; 778 779 // 服務員,負責組合菜單,負責組裝每個菜和具體的實現(xiàn)者。 780 var Waiter = function () { 781 var menuCommand = new MenuCommand(); 782 783 // 客戶點菜 784 this.orderDish = function (cmd) { 785 var hotCook = new HotCook(); 786 var coolCook = new CoolCook(); 787 788 if (cmd instanceof DuckCommand) { 789 cmd.setCookApi(hotCook); 790 } else if (cmd instanceof ChopCommand) { 791 cmd.setCookApi(hotCook); 792 } else if (cmd instanceof PorkCommand) { 793 cmd.setCookApi(coolCook); 794 } 795 796 menuCommand.addCommand(cmd); 797 }; 798 799 // 點菜完畢 800 this.orderOver = function () { 801 menuCommand.execute(); 802 }; 803 }; 804 805 var waiter = new Waiter(); 806 var chop = new ChopCommand(); 807 var duck = new DuckCommand(); 808 var pork = new PorkCommand(); 809 810 waiter.orderDish(chop); 811 waiter.orderDish(duck); 812 waiter.orderDish(pork); 813 814 waiter.orderOver(); 815 816 }()); 817 818 (function () { 819 // 隊列請求 820 821 function createCommand(name) { 822 function Command(tableNum) { 823 this.cookApi = null; 824 this.tableNum = tableNum; 825 } 826 827 Command.prototype = { 828 setCookApi: function (cookApi) { 829 this.cookApi = cookApi; 830 }, 831 execute: function () { 832 this.cookApi.cook(this.tableNum, name); 833 } 834 }; 835 836 return Command; 837 } 838 839 var ChopCommand = createCommand('綠豆排骨煲'); 840 var DuckCommand = createCommand('北京烤鴨'); 841 842 var CommandQueue = { 843 cmds: [], 844 addMenu: function (menu) { 845 var cmds = menu.getCommands(); 846 for (var i = 0, len = cmds.length; i < len; i++) { 847 this.cmds.push(cmds[i]); 848 } 849 }, 850 getOneCommand: function () { 851 return this.cmds.length ? this.cmds.shift() : null; 852 } 853 }; 854 855 var MenuCommand = function () { 856 this.col = []; 857 }; 858 MenuCommand.prototype = { 859 addCommand: function (cmd) { 860 this.col.push(cmd); 861 }, 862 setCookApi: function (cookApi) { 863 }, 864 getTableNum: function () { 865 return 0; 866 }, 867 getCommands: function () { 868 return this.col; 869 }, 870 execute: function () { 871 CommandQueue.addMenu(this); 872 } 873 }; 874 875 var HotCook = function (name) { 876 this.name = name; 877 }; 878 HotCook.prototype = { 879 cook: function (tableNum, name) { 880 var cookTime = parseInt(10 * Math.random() + 3); 881 console.log(this.name + '廚師正在為' + tableNum + '號桌做:' + name); 882 883 var me = this; 884 setTimeout(function () { 885 console.log(me.name + '廚師為' + tableNum + '號桌做好了:' + name + ',共計耗時=' + cookTime + ''); 886 }, cookTime * 1000); 887 }, 888 run: function () { 889 var me = this; 890 setTimeout(function () { 891 var cmd; 892 893 while ((cmd = CommandQueue.getOneCommand())) { 894 cmd.setCookApi(me); 895 cmd.execute(); 896 } 897 }, 1000); 898 } 899 }; 900 901 var Waiter = function () { 902 this.menuCommand = new MenuCommand(); 903 }; 904 Waiter.prototype = { 905 orderDish: function (cmd) { 906 this.menuCommand.addCommand(cmd); 907 }, 908 orderOver: function () { 909 this.menuCommand.execute(); 910 } 911 }; 912 913 var c1 = new HotCook('張三'); 914 c1.run(); 915 916 for (var i = 0; i < 5; i++) { 917 var waiter = new Waiter(); 918 var chop = new ChopCommand(i); 919 var duck = new DuckCommand(i); 920 921 waiter.orderDish(chop); 922 waiter.orderDish(duck); 923 924 waiter.orderOver(); 925 } 926 927 }()); 928 929 function test() { 930 // 日志請求 931 // TODO 該示例在寫入文件內(nèi)容的時候并不能把實例的原型對象序列化, 932 // 因此讀取文件內(nèi)容后,反序列化后沒有原型對應的方法 933 var fs = require('fs'); 934 var Promise = require('d:\\node\\node_modules\\rsvp'); 935 936 var FileOpeUtil = { 937 readFile: function (pathName) { 938 var def = Promise.defer(); 939 940 fs.open(pathName, 'r', function opened(err, fd) { 941 if (err) { 942 def.reject(); 943 fs.close(fd); 944 throw err; 945 } 946 947 var readBuffer = new Buffer(1024); 948 var bufferOffset = 0; 949 var bufferLength = readBuffer.length; 950 var filePosition = null; 951 952 fs.read( 953 fd, 954 readBuffer, 955 bufferOffset, 956 bufferLength, 957 filePosition, 958 function read(err, readBytes) { 959 if (err) { 960 def.reject(err); 961 fs.close(fd); 962 return; 963 } 964 965 if (readBytes >= 0) { 966 try { 967 def.resolve(JSON.parse(readBuffer.slice(0, readBytes).toString('utf8'))); 968 } catch (e) { 969 def.reject(e); 970 } 971 972 fs.close(fd); 973 } 974 } 975 ); 976 }); 977 978 return def.promise; 979 }, 980 writeFile: function (pathName, list) { 981 var def = Promise.defer(); 982 983 fs.open(pathName, 'w', function opened(err, fd) { 984 if (err) { 985 def.reject(); 986 fs.close(fd); 987 throw err; 988 } 989 990 var writeBuffer = new Buffer(JSON.stringify(list)); 991 var bufferPosition = 0; 992 var bufferLength = writeBuffer.length; 993 var filePosition = null; 994 995 fs.write( 996 fd, 997 writeBuffer, 998 bufferPosition, 999 bufferLength, 1000 filePosition, 1001 function wrote(err, written) { 1002 if (err) { 1003 def.reject(err); 1004 fs.close(fd); 1005 return; 1006 } 1007 1008 console.log('wrote ' + written + ' bytes'); 1009 def.resolve(written); 1010 fs.close(fd); 1011 } 1012 ); 1013 }); 1014 1015 return def.promise; 1016 } 1017 }; 1018 1019 function createCommand(name) { 1020 function Command(tableNum) { 1021 this.cookApi = null; 1022 this.tableNum = tableNum; 1023 } 1024 1025 Command.prototype = { 1026 setCookApi: function (cookApi) { 1027 this.cookApi = cookApi; 1028 }, 1029 execute: function () { 1030 this.cookApi.cook(this.tableNum, name); 1031 } 1032 }; 1033 1034 return Command; 1035 } 1036 1037 var ChopCommand = createCommand('綠豆排骨煲'); 1038 var DuckCommand = createCommand('北京烤鴨'); 1039 1040 var MenuCommand = function () { 1041 this.col = []; 1042 }; 1043 MenuCommand.prototype = { 1044 addCommand: function (cmd) { 1045 this.col.push(cmd); 1046 }, 1047 setCookApi: function (cookApi) { 1048 }, 1049 getTableNum: function () { 1050 return 0; 1051 }, 1052 getCommands: function () { 1053 return this.col; 1054 }, 1055 execute: function () { 1056 CommandQueue.addMenu(this); 1057 } 1058 }; 1059 1060 var HotCook = function (name) { 1061 this.name = name; 1062 }; 1063 HotCook.prototype = { 1064 cook: function (tableNum, name) { 1065 var cookTime = parseInt(10 * Math.random() + 3); 1066 console.log(this.name + '廚師正在為' + tableNum + '號桌做:' + name); 1067 1068 var me = this; 1069 setTimeout(function () { 1070 console.log(me.name + '廚師為' + tableNum + '號桌做好了:' + name + ',共計耗時=' + cookTime + ''); 1071 }, cookTime * 1000); 1072 }, 1073 run: function () { 1074 var me = this; 1075 setTimeout(function () { 1076 var cmd; 1077 1078 while ((cmd = CommandQueue.getOneCommand())) { 1079 cmd.setCookApi(me); 1080 cmd.execute(); 1081 break; 1082 } 1083 }, 1000); 1084 } 1085 }; 1086 1087 var Waiter = function () { 1088 this.menuCommand = new MenuCommand(); 1089 }; 1090 Waiter.prototype = { 1091 orderDish: function (cmd) { 1092 this.menuCommand.addCommand(cmd); 1093 }, 1094 orderOver: function () { 1095 this.menuCommand.execute(); 1096 } 1097 }; 1098 1099 1100 var CommandQueue = { 1101 cmds: [], 1102 addMenu: function (menu) { 1103 var cmds = menu.getCommands(); 1104 for (var i = 0, len = cmds.length; i < len; i++) { 1105 this.cmds.push(cmds[i]); 1106 } 1107 FileOpeUtil.writeFile('./test.txt', this.cmds); 1108 }, 1109 getOneCommand: function () { 1110 var cmd = null; 1111 1112 if (this.cmds.length) { 1113 cmd = this.cmds.shift(); 1114 FileOpeUtil.writeFile('./test.txt', this.cmds); 1115 } 1116 1117 return cmd; 1118 } 1119 }; 1120 1121 var FILE_NAME = './test.txt'; 1122 1123 FileOpeUtil.readFile(FILE_NAME) 1124 .then(function (data) { 1125 console.log(data); 1126 data.map(function () { 1127 1128 }); 1129 1130 CommandQueue.cmds = data; 1131 main(); 1132 }, function () { 1133 main(); 1134 }); 1135 1136 function main() { 1137 var c1 = new HotCook('張三'); 1138 c1.run(); 1139 1140 for (var i = 0; i < 5; i++) { 1141 var waiter = new Waiter(); 1142 var chop = new ChopCommand(i); 1143 var duck = new DuckCommand(i); 1144 1145 waiter.orderDish(chop); 1146 waiter.orderDish(duck); 1147 1148 waiter.orderOver(); 1149 } 1150 } 1151 } 1152 1153 /* 1154 用于崩潰恢復的命令日志 1155 1156 命令日志的一個有趣的用途是在程序崩潰后恢復其狀態(tài)。在前面這個示例中,可以用XHR把經(jīng)過序列化處理的命令記錄到服務器上。用戶下次訪問該網(wǎng)頁的時候,系統(tǒng)可以找出這些命令并用其將畫布上的圖案精確恢復到瀏覽器關閉時的狀態(tài)。這可以替用戶把應用程序狀態(tài)保管下來,以便其撤銷先前的任何一次瀏覽器會話中執(zhí)行的操作。如果應用系統(tǒng)比較復雜,那么這種類型的命令日志會很大的存儲需求。為此你可以提供一個按鈕,用戶可以用它提交到當時為止的所有操作,從而清空命令棧。 1157 */ 1158 1159 /* 1160 命令模式的適用場合 1161 1162 1.如果需要抽象出需要執(zhí)行的動作,并參數(shù)化這些對象,可以選用命令模式。將這些需要執(zhí)行的動作抽象成為命令,然后實現(xiàn)命令的參數(shù)化配置。 1163 2.如果需要在不同的時刻指定,排列和執(zhí)行請求。將這些請求封裝成為命令對象,然后實現(xiàn)請求隊列化。 1164 3.如果需要支持取消操作,可以選用,通過管理命令對象,能很容易的實現(xiàn)命令的恢復和重做功能。 1165 4.如果需要支持當系統(tǒng)奔潰時,能將系統(tǒng)的操作功能重新執(zhí)行一遍時。將這些操作功能的請求封裝成命令對象,然后實現(xiàn)日志命令,就可以在系統(tǒng)恢復以后,通過日志獲取命令列表,從而重新執(zhí)行一遍功能。 1166 5.在需要事務的系統(tǒng)中,命令模式提供了對事務進行建模的方法。 1167 1168 1169 命令模式之利 1170 1171 1.更松散的耦合 1172 命令模式使得發(fā)起命令的對象--客戶端,和具體實現(xiàn)命令的對象--接收者對象完全解耦,也就是說發(fā)起命令的對象完全不知道具體實現(xiàn)對象是誰,也不知道如何實現(xiàn)。 1173 2.更動態(tài)的控制 1174 命令模式把請求封裝起來,可以動態(tài)地對它進行參數(shù)化,隊列花和日志化等操作,從而使得系統(tǒng)更靈活。 1175 3.很自然的復合命令 1176 很容易地組合符合命令,也就是宏命令。 1177 4.更好的擴展性 1178 1179 1180 1181 命令模式之弊 1182 1183 如果一個命令對象只包裝了一個方法調(diào)用,而且其唯一目的就是這層對象包裝的話,那么這種做法是一種浪費。如果你不需要命令模式給予的任何額外特性,也不需要具有一致接口的類所帶來的模塊性,那么直接使用方法引用而不是完整的命令對象也許更恰當。命令對象也會增加代碼調(diào)試的難度,因為在應用了命令模式之后原有的方法之上又多了一層可能出錯的代碼。 1184 1185 1186 相關模式 1187 1188 命令模式和組合模式 1189 可以組合使用 1190 宏命令的功能就可以使用組合模式。 1191 1192 命令模式和備忘錄模式 1193 可以組合使用 1194 在實現(xiàn)可撤銷功能時,如果采用保存命令執(zhí)行前的狀態(tài),撤銷的時候就把狀態(tài)恢復,就可以考慮使用備忘錄模式。 1195 1196 命令模式和模板方法模式 1197 命令模式可以作為模板方法的一種替代模式,也就是說命令模式可以模仿實現(xiàn)模板方法模式的功能。 1198 */ 1199 1200 1201 /* Title: Command 1202 Description: creates objects which encapsulate actions and parameters 1203 */ 1204 1205 (function () { 1206 1207 var CarManager = { 1208 1209 /* request information */ 1210 requestInfo: function (model, id) { 1211 return 'The purchase info for ' + model + ' with ID ' + id + ' is being processed...'; 1212 }, 1213 1214 /* purchase the car */ 1215 buyVehicle: function (model, id) { 1216 return 'You have successfully purchased Item ' + id + ', a ' + model + '.'; 1217 } 1218 1219 }; 1220 1221 CarManager.execute = function (commad) { 1222 return CarManager[commad.request](commad.model, commad.carID); 1223 }; 1224 1225 var actionA = CarManager.execute({request: 'requestInfo', model: 'Ford Mondeo', carID: '543434'}); 1226 console.log(actionA); 1227 var actionB = CarManager.execute({request: 'buyVehicle', model: 'Ford Mondeo', carID: '543434'}); 1228 console.log(actionB); 1229 1230 })(); 1231 1232 1233 // http://www.joezimjs.com/javascript/javascript-design-patterns-command/ 1234 var EnableAlarm = function (alarm) { 1235 this.alarm = alarm; 1236 } 1237 EnableAlarm.prototype.execute = function () { 1238 this.alarm.enable(); 1239 } 1240 1241 var DisableAlarm = function (alarm) { 1242 this.alarm = alarm; 1243 } 1244 DisableAlarm.prototype.execute = function () { 1245 this.alarm.disable(); 1246 } 1247 1248 var ResetAlarm = function (alarm) { 1249 this.alarm = alarm; 1250 } 1251 ResetAlarm.prototype.execute = function () { 1252 this.alarm.reset(); 1253 } 1254 1255 var SetAlarm = function (alarm) { 1256 this.alarm = alarm; 1257 } 1258 SetAlarm.prototype.execute = function () { 1259 this.alarm.set(); 1260 } 1261 1262 var alarms = [/* array of alarms */], 1263 i = 0, len = alarms.length; 1264 1265 for (; i < len; i++) { 1266 var enable_alarm = new EnableAlarm(alarms[i]), 1267 disable_alarm = new DisableAlarm(alarms[i]), 1268 reset_alarm = new ResetAlarm(alarms[i]), 1269 set_alarm = new SetAlarm(alarms[i]); 1270 1271 new Button('enable', enable_alarm); 1272 new Button('disable', disable_alarm); 1273 new Button('reset', reset_alarm); 1274 new Button('set', set_alarm); 1275 } 1276 1277 1278 var makeEnableCommand = function (alarm) { 1279 return function () { 1280 alarm.enable(); 1281 } 1282 } 1283 1284 var makeDisableCommand = function (alarm) { 1285 return function () { 1286 alarm.disable(); 1287 } 1288 } 1289 1290 var makeResetCommand = function (alarm) { 1291 return function () { 1292 alarm.reset(); 1293 } 1294 } 1295 1296 var makeSetCommand = function (alarm) { 1297 return function () { 1298 alarm.set(); 1299 } 1300 } 1301 1302 </script> 1303 </body> 1304 </html>

?

轉(zhuǎn)載于:https://www.cnblogs.com/webFrontDev/archive/2013/05/13/3075865.html

總結(jié)

以上是生活随笔為你收集整理的javascript设计模式--命令模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

黄色免费网战 | 国产视频一区二区在线观看 | 欧亚日韩精品一区二区在线 | 国产精品福利久久久 | 一级黄色在线视频 | 婷婷网站天天婷婷网站 | 日本精品久久久一区二区三区 | av中文字幕在线播放 | 中文视频一区二区 | 国产精品综合av一区二区国产馆 | 18久久久 | 亚洲视频专区在线 | 久久天天躁夜夜躁狠狠躁2022 | 亚洲精品乱码久久久久久蜜桃91 | 久久精品麻豆 | 黄色av三级在线 | 免费看一级特黄a大片 | 亚洲伦理精品 | 日韩av中文在线 | 综合网天天色 | 国产香蕉视频在线播放 | 亚州精品天堂中文字幕 | 久久免费久久 | 在线激情影院一区 | 亚洲成 人精品 | 亚洲国产中文字幕 | 久久免费视频在线观看30 | 久久国产精品免费一区二区三区 | 国产日韩精品一区二区三区在线 | 国产一区二区在线免费 | 香蕉97视频观看在线观看 | 亚洲成人动漫在线观看 | 欧日韩在线视频 | 四虎影视精品 | av福利网址导航 | 亚洲国产一区av | 中文字幕成人在线观看 | www.啪啪.com| 久久成人国产精品免费软件 | 国产精品久久久精品 | 激情在线免费视频 | 中文字幕在线一二 | 亚洲精品国久久99热 | 天天玩夜夜操 | 国产亚洲在 | 欧美日韩一区二区三区不卡 | 97色在线观看 | 亚洲色综合 | 综合网婷婷 | 综合色婷婷| 精品国偷自产国产一区 | 在线亚洲欧美视频 | 日本性生活免费看 | 婷婷去俺也去六月色 | 亚洲精品久| 国产精品久久久久久妇 | 91一区二区三区久久久久国产乱 | 看毛片网站 | 欧美在线不卡一区 | 久久久久电影网站 | 久久兔费看a级 | 五月婷婷激情综合 | 国产字幕在线观看 | 中文字幕在线观 | 午夜精品视频免费在线观看 | 一区二区三区在线免费观看 | 中文字幕中文字幕在线一区 | 91精品视频免费 | 射久久 | 97在线观看免费高清完整版在线观看 | 精品视频免费观看 | 欧美精品天堂 | 色婷婷天天干 | 精品高清视频 | 免费91在线观看 | 99综合久久 | 婷婷5月色| 日韩免费视频一区二区 | 99一级片 | 婷婷六月激情 | 在线播放国产一区二区三区 | 国产精品资源 | 三级av在线免费观看 | 免费在线黄色av | 国产精品久久久久久99 | 青青网视频 | 日韩在线观看视频网站 | 日韩小视频网站 | 99精品视频在线观看播放 | 国产精品理论视频 | 99精品视频在线观看视频 | 毛片美女网站 | 成人午夜影院在线观看 | 蜜桃av人人夜夜澡人人爽 | 国产女人免费看a级丨片 | 丁香九月婷婷综合 | 成人国产精品 | 在线播放亚洲激情 | 国产精品无| 97激情影院 | 成 人 黄 色 视频 免费观看 | 亚洲国产剧情 | 日韩精品一区二区在线视频 | 欧美日韩免费视频 | 国产尤物一区二区三区 | 国产精品video爽爽爽爽 | 日韩激情中文字幕 | 久久不射电影院 | 日本在线观看一区 | 中文字幕一区二区三区在线观看 | 亚洲成人资源在线观看 | 91麻豆精品国产91久久久久久 | 国产韩国精品一区二区三区 | 国产精品麻 | 免费麻豆视频 | 少妇bbbb揉bbbb日本 | 久久国产精品免费观看 | 99999精品 | 亚洲狠狠干 | 中文字幕资源网 国产 | 99久国产| 丁香花在线观看视频在线 | avav99| 国产91成人在在线播放 | 国产一二三精品 | 国产色视频123区 | 精品a在线 | 国产精品国产毛片 | 99精品偷拍视频一区二区三区 | 视频在线99re| av软件在线观看 | 韩国精品在线观看 | 亚洲欧美精品一区 | www色com| 最近2019好看的中文字幕免费 | 一区二区三区日韩视频在线观看 | www.婷婷色| 亚洲国产精品日韩 | 天天爱天天操天天爽 | 999一区二区三区 | 欧洲高潮三级做爰 | 国产一级二级在线观看 | 黄色电影在线免费观看 | 五月婷婷激情综合网 | 美女免费视频一区二区 | 日韩视频在线不卡 | 国产一在线精品一区在线观看 | 国产96在线| 视频成人 | 欧美日韩一区二区三区视频 | 国产精品一区二区在线看 | 亚洲精品综合在线观看 | 婷婷看片 | 偷拍久久久 | 午夜精品久久久久久久久久 | 2020天天干夜夜爽 | 久久久高清免费视频 | 99c视频高清免费观看 | 99视频在线免费观看 | 在线观看深夜福利 | 在线免费观看视频 | 香蕉视频18 | 婷婷成人亚洲综合国产xv88 | 亚洲视频精品 | 久久久久久蜜av免费网站 | 国产精品久久久久久久久免费看 | 一区二区不卡高清 | 国产又粗又猛又黄又爽的视频 | 精品久久久久久久久久久院品网 | 探花视频在线观看免费 | 一级性视频| 亚洲精品国产精品国自产观看 | 久久久亚洲国产精品麻豆综合天堂 | 久久久影视 | 国产91大片 | 精品在线视频播放 | 黄色大片入口 | 欧美日韩国产在线 | 日本字幕网 | 丁香免费视频 | 91麻豆操| 久久久久久久久福利 | 国产精品亚州 | 亚洲在线观看av | 欧美一级大片在线观看 | 国产不卡av在线播放 | 色婷五月天 | 久草视频视频在线播放 | 91看片一区二区三区 | 色噜噜狠狠色综合中国 | 亚洲国产精品推荐 | 中文字幕欲求不满 | 在线成人免费电影 | 免费久久久 | 天天综合91 | 在线观看你懂的网址 | 97在线公开视频 | 免费在线观看黄 | 国产不卡在线看 | 久久激情婷婷 | 免费99精品国产自在在线 | 九九免费精品视频在线观看 | 国产欧美精品xxxx另类 | 欧美日韩后 | 久久久精华网 | 在线观看国产www | 亚洲综合小说电影qvod | 色视频成人在线观看免 | 在线观看午夜 | 精品亚洲成a人在线观看 | 在线a视频免费观看 | jizzjizzjizz亚洲 | 久久久国产一区二区三区四区小说 | 日日爽视频 | 九九九九色 | 91资源在线免费观看 | 国产成人精品一区二区三区福利 | 91九色最新 | 最新av免费在线观看 | 国产精品永久久久久久久久久 | 精品国产成人av在线免 | 亚洲视频 视频在线 | 丁香色天天 | 91精品国产高清自在线观看 | 2023年中文无字幕文字 | 97综合在线 | 九九免费在线观看视频 | 中文字幕国产 | 欧美精品v国产精品v日韩精品 | 中文字幕在线一二 | 国内精品免费久久影院 | 中文字幕色在线视频 | 一级一级一片免费 | 97精产国品一二三产区在线 | 欧美日韩一区久久 | 亚洲国产中文在线观看 | 久久成人黄色 | 91精品视频在线观看免费 | 91中文字幕在线视频 | 久草www | 最新日韩视频 | 中文字幕亚洲精品日韩 | 九九九九热精品免费视频点播观看 | 久久美女免费视频 | 日韩精品一区二区免费 | 视色网站| 日本成人中文字幕在线观看 | 日韩性片 | 免费在线国产 | 99精品电影 | 91麻豆精品国产91久久久无需广告 | 欧美色综合天天久久综合精品 | 国产精品欧美久久久久三级 | 综合婷婷丁香 | 91av超碰| 亚洲综合丁香 | 欧美极品一区二区三区 | 国产精品久久久久国产精品日日 | 97免费在线观看 | 亚洲精品午夜视频 | 精品久久精品久久 | 91精品久久久久 | 青青河边草观看完整版高清 | 天海冀一区二区三区 | 中文字幕人成人 | 国产超碰97| 在线国产能看的 | 人人干人人草 | 亚洲区二区 | 欧美成人一二区 | 久久免费看 | 久久久久久毛片 | 日韩二区在线 | 麻豆免费在线视频 | 在线导航av | 六月丁香激情网 | 久久精品久久精品久久 | 久久久久久久久久久久国产精品 | 亚洲乱码国产乱码精品天美传媒 | 精品在线播放视频 | 日韩精品1区2区 | 日韩av不卡在线 | 亚洲成av | 欧美激情综合五月色丁香小说 | 99久久电影 | 免费成人在线网站 | 国产在线视频一区二区三区 | 久久免费美女视频 | 国产精品激情在线观看 | 精品免费国产一区二区三区四区 | 麻花豆传媒mv在线观看 | 亚洲精品视频偷拍 | 一级黄色大片在线观看 | 国产精品白浆 | av免费看av | 午夜国产一区二区 | 欧美日韩在线视频免费 | 久久永久视频 | 久久久久成人免费 | 国产精品久久久久国产精品日日 | 一区二区精品在线观看 | 成年美女黄网站色大片免费看 | 亚洲精品在线观看视频 | 偷拍视频一区 | 粉嫩av一区二区三区四区 | 久久特级毛片 | 成年美女黄网站色大片免费看 | 在线免费成人 | 91av播放 | av中文在线影视 | 在线91色 | 亚洲精品成人网 | 久久99中文字幕 | 日韩在线播放av | 国产区在线看 | 免费在线激情电影 | 欧美一级看片 | 亚洲精选视频在线 | 一区二区三区在线看 | 天堂网中文在线 | 久久久免费看视频 | 综合久久久久久 | 成年人视频在线免费 | 国内一级片在线观看 | 91精品久久久久 | 97在线成人| 久久国产一区二区 | 国产成人精品一区二三区 | 日韩精品免费在线视频 | 特级毛片在线 | 黄色网址国产 | 天天干,天天操,天天射 | 国产精品mv在线观看 | 久久久久久影视 | 精品国产一区二区三区免费 | 久操视频在线免费看 | 久草在线 | 黄色官网在线观看 | 香蕉视频在线看 | 日韩 精品 一区 国产 麻豆 | 国产精品一码二码三码在线 | 亚洲精品久久久久中文字幕二区 | 碰超在线97人人 | 婷婷伊人综合亚洲综合网 | 美女很黄免费网站 | 1000部国产精品成人观看 | 97超碰人人网 | 中文字幕电影网 | 免费观看国产成人 | 亚洲成人免费 | 国产精品视频永久免费播放 | 日日夜夜人人天天 | 婷婷丁香久久五月婷婷 | 国语对白少妇爽91 | 2019中文最近的2019中文在线 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产黄影院色大全免费 | 日本在线观看中文字幕无线观看 | 天天色天天上天天操 | 久久99精品波多结衣一区 | 亚洲国产精彩中文乱码av | 久久超碰免费 | 国产成人精品一区二三区 | 国产成人精品av在线观 | 亚洲视频在线视频 | 丁香婷婷综合激情 | 97精品国产一二三产区 | 欧美大片www | 91污视频在线 | 久久久久久久福利 | 亚洲成人精品久久久 | 在线视频 成人 | 狠狠的操| 成人电影毛片 | 日日操日日插 | 国产视频一区二区三区在线 | 久久国产午夜精品理论片最新版本 | 亚洲精品美女久久久久 | 一区在线电影 | 亚洲欧洲精品一区二区精品久久久 | 国产乱码精品一区二区三区介绍 | 黄色一级在线视频 | 日韩精品一区二区三区免费观看视频 | 四虎在线观看视频 | 黄色av成人在线 | 91精品免费在线观看 | 黄色看片 | 蜜臀av夜夜澡人人爽人人 | 丰满少妇对白在线偷拍 | 天堂视频中文在线 | 91麻豆文化传媒在线观看 | 99成人精品 | 久久久久久久久久久网 | 日韩免费一区二区 | 91精品国产99久久久久 | 三级免费黄色 | 欧美视频xxx| 天天操天天干天天干 | 99福利片 | 欧美在线99 | 久久综合狠狠综合 | 亚洲视频六区 | 国产精品嫩草影视久久久 | 99中文视频在线 | 日本中文在线观看 | 亚洲精品www久久久 www国产精品com | 久久精品99国产国产 | 久久精品91久久久久久再现 | 国产成人中文字幕 | 日韩一区二区三区高清免费看看 | 亚洲精品字幕在线 | 亚洲精品免费视频 | 91视频免费看片 | 深爱婷婷久久综合 | 欧美性久久久久久 | 一区二区三区播放 | 精品在线播放 | 草久在线视频 | 香蕉视频在线免费看 | 久草视频手机在线 | zzijzzij日本成熟少妇 | av三级在线免费观看 | 中文字幕欧美激情 | 日韩免费在线观看 | 日本久久精品 | 天天色综合久久 | 黄污视频网站大全 | 草免费视频 | 狠狠色丁香婷婷 | 日韩高清在线观看 | 国产精品久久一卡二卡 | 色橹橹欧美在线观看视频高清 | 亚洲天堂自拍视频 | 色在线免费 | 成人黄视频 | 在线免费观看国产精品 | 天天做天天爱天天综合网 | 日韩美在线 | 精品国产欧美一区二区三区不卡 | 亚洲久草在线视频 | 97久久久免费福利网址 | 国产精品欧美日韩 | 黄色三级网站在线观看 | 日本精品va在线观看 | 精品xxx | 99精品免费久久久久久久久 | 成人高清在线观看 | 911国产在线观看 | 超碰在线97国产 | 久久香蕉电影网 | 日韩在线不卡 | 瑞典xxxx性hd极品 | 天堂v中文 | 欧美日韩91 | 最近中文字幕视频完整版 | 韩国一区二区三区视频 | 在线观看视频一区二区 | 亚洲精品乱码久久久久久写真 | 成年人免费看的视频 | 欧美精品乱码99久久影院 | 麻花传媒mv免费观看 | 久99久精品视频免费观看 | 狠狠久久综合 | 成人黄色电影在线 | 欧美淫视频 | 欧洲精品久久久久毛片完整版 | 久久草草影视免费网 | 国产一线二线三线在线观看 | 亚洲欧美国产视频 | 欧美日韩另类在线 | 欧美一级裸体视频 | 日韩在线观看的 | 色噜噜在线观看视频 | 97日日碰人人模人人澡分享吧 | 美女视频永久黄网站免费观看国产 | 亚洲视频免费在线看 | 欧美视频一区二 | 99re在线视频观看 | 国产日韩欧美视频在线观看 | 日本特黄特色aaa大片免费 | adn—256中文在线观看 | 久久看毛片 | 91精品在线观看视频 | 国产成人一区三区 | 久久精品之 | 亚洲精品播放 | 成人动漫一区二区 | 91精品一| 不卡电影一区二区三区 | 国产精品免费一区二区 | 日日夜夜噜| 午夜精品久久久久久久99婷婷 | 国产成人三级 | 天天爱天天射 | 一区二区三区四区在线免费观看 | 久久久九九 | 91精品资源 | 一级黄色片在线 | 成人宗合网 | 久久久精品欧美一区二区免费 | 久久久亚洲电影 | 中文字幕在线专区 | 久久视频二区 | 激情欧美一区二区三区 | 亚洲欧洲成人精品av97 | 成人在线观看影院 | 麻豆 videos| 草久电影 | 综合网伊人 | 国产精品 中文字幕 亚洲 欧美 | 日本中文在线播放 | 色婷婷综合成人av | 狠狠色丁香久久婷婷综 | 色综合久久88色综合天天 | 久久久久久久久久久福利 | 9999国产精品 | 久久久午夜精品理论片中文字幕 | 日本精油按摩3 | 久久久久久亚洲精品 | 在线观看一区二区视频 | 激情五月视频 | 在线免费黄色av | 午夜国产福利在线 | 青草视频网 | 亚洲狠狠婷婷综合久久久 | 久艹在线观看视频 | 麻豆小视频在线观看 | 日韩网站一区二区 | 天堂在线一区二区 | 偷拍福利视频一区二区三区 | 在线影院av| 久久久99国产精品免费 | 亚洲有 在线 | 日韩成人精品一区二区三区 | 波多野结衣在线播放视频 | 久久久久成人精品亚洲国产 | 久久国产手机看片 | av免费网站在线观看 | 人人讲下载 | 丁香婷婷基地 | 欧美极品少妇xbxb性爽爽视频 | 美女免费av | 精品国产一区二区三区在线 | 中文不卡视频在线 | 欧美在线视频日韩 | 免费在线观看av片 | 美女网站在线观看 | 日韩av区 | 成人精品一区二区三区中文字幕 | 成人久久18免费网站麻豆 | 国产成人一区二区三区在线观看 | 午夜在线观看影院 | 婷婷电影在线观看 | 国产一区二区三精品久久久无广告 | 免费三级骚 | 色婷婷综合久久久中文字幕 | 色视频成人在线观看免 | 韩国av一区二区三区在线观看 | 2019免费中文字幕 | 九九精品视频在线看 | 国产成人久久精品 | 亚洲成人av免费 | av福利免费 | 亚洲成av人影院 | 国产一级视频在线观看 | 欧美成人日韩 | 69久久99精品久久久久婷婷 | 亚洲视频h | 日本mv大片欧洲mv大片 | 欧美色伊人 | 日韩av女优视频 | 草久久av| 日韩在线视频免费播放 | 亚洲国产69 | 久久免费中文视频 | 久久精选视频 | 色综合久久久久综合体 | 国产精品二区三区 | 夜夜操夜夜干 | 久久久久久欧美二区电影网 | 一区二区三区av在线 | 亚洲精品在线电影 | 婷婷在线精品视频 | 免费a级毛片在线看 | 免费能看的黄色片 | 亚洲最新精品 | 国产亚洲一区二区在线观看 | 天天干天天插 | 精品中文字幕视频 | 精品视频123区在线观看 | 国产成人一二片 | 亚洲 av网站 | 亚洲涩涩涩涩涩涩 | 久九视频 | 久久精品中文 | 天天超碰| 亚洲撸撸 | 在线免费观看成人 | 欧美精品做受xxx性少妇 | 国产专区精品视频 | 五月天激情视频在线观看 | 色综合久久久久 | 日批在线看 | ,午夜性刺激免费看视频 | 国产成人亚洲在线观看 | 96av视频 | 国产一区二区三区网站 | 欧美一区二区免费在线观看 | 在线观看一二三区 | 国产免费视频一区二区裸体 | 国产色网 | 日韩黄色免费 | 久久激情视频免费观看 | 久久成人黄色 | 中文字幕av电影下载 | 91香蕉视频| 国内免费久久久久久久久久久 | 亚洲午夜精品一区二区三区电影院 | 波多野结衣在线观看一区二区三区 | 一区二区三区在线不卡 | 日韩v欧美v日本v亚洲v国产v | 精品一区二区三区四区在线 | 五月婷婷在线观看视频 | 国产自制av| 一二三区在线 | 在线国产视频观看 | 国产精品高清免费在线观看 | 黄色小说在线免费观看 | 国产精品第7页 | 国产大片黄色 | 国产精品美女久久久久久2018 | 中文网丁香综合网 | 国产精品入口麻豆 | 日日干日日 | 黄色aaa毛片 | 日韩精品免费一区 | 亚洲男男gⅴgay双龙 | 91精品国产麻豆国产自产影视 | 四虎国产精品永久在线国在线 | 日韩欧美国产激情在线播放 | 亚洲欧美激情精品一区二区 | 视频国产精品 | 狠狠地日 | 国产99久久久国产精品免费看 | 国产日产亚洲精华av | 久草国产精品 | 欧美日本啪啪无遮挡网站 | 精品高清美女精品国产区 | 中文字幕91| 婷婷国产v亚洲v欧美久久 | 亚洲精品一区二区三区四区高清 | 久久久精品亚洲 | 韩国视频一区二区三区 | 超碰免费公开 | 欧美精品久久久久久 | 国产裸体视频bbbbb | 99视频国产在线 | 99在线免费视频 | 欧美日韩免费一区二区三区 | 日本在线观看中文字幕无线观看 | 狠狠躁日日躁狂躁夜夜躁av | 久久免费的精品国产v∧ | 国产亚洲视频中文字幕视频 | 日韩视频 一区 | 蜜臀一区二区三区精品免费视频 | 五月婷婷视频 | 一区二区三区视频 | 2024国产精品视频 | 在线日韩视频 | 国内外成人在线视频 | 9草在线 | 久久精品婷婷 | 99在线视频网站 | 精品久久久久久久久久国产 | 亚洲欧美国产视频 | 在线观看 亚洲 | 国产精品久久精品 | 亚洲欧美日韩一二三区 | 久久精品一区二区三区中文字幕 | 国产精品久久久久久久久搜平片 | 狠狠操狠狠操 | 亚洲电影图片小说 | 在线观看亚洲成人 | 免费欧美高清视频 | 国产精品一区二区久久精品爱微奶 | 在线观看日韩国产 | 久久视频在线免费观看 | 欧美日一级片 | 中文字幕在线免费观看视频 | 日日夜夜综合网 | 青青视频一区 | 亚洲另类视频在线观看 | 日韩成人在线免费观看 | 国产精品久久9 | 成人欧美一区二区三区在线观看 | 久影院| 天天干天天干天天干天天干天天干天天干 | 日本高清中文字幕有码在线 | 日韩在线观看视频一区二区三区 | 免费的黄色av | 成人av一级片 | 中文字幕在线观看视频一区 | 欧美精品国产精品 | 日日激情| 四虎国产精品成人免费4hu | 蜜桃传媒一区二区 | 在线观看国产一区二区 | 国产午夜三级一区二区三桃花影视 | 亚洲综合在线播放 | 久久香蕉一区 | 精品一区在线看 | 毛片网免费| 日韩激情影院 | 激情婷婷 | av在线看网站 | 69久久99精品久久久久婷婷 | 亚洲精品久久久久58 | 久草在线观看资源 | 久久精品99国产精品日本 | 欧美激情精品久久久久久 | 99精品国产兔费观看久久99 | 高清色免费| av在线色 | 夜夜躁天天躁很躁波 | av电影免费在线 | av电影中文字幕在线观看 | 国产成人精品av在线观 | 手机av看片 | 青春草国产视频 | 日产乱码一二三区别在线 | 99热在线观看免费 | 亚洲精品国产精品久久99 | 欧美性成人 | 国产精品福利小视频 | 黄色资源在线观看 | 超碰av在线| 国产一级久久久 | 中文字幕在线字幕中文 | 中文字幕久久亚洲 | 麻豆91在线观看 | 国产精品 中文字幕 亚洲 欧美 | 国产一区精品在线 | 精品一区二区久久久久久久网站 | 成人av网站在线播放 | 一区二区视频欧美 | 精品久久一区二区 | 中文在线最新版天堂 | av在线之家电影网站 | 欧美乱码精品一区 | 免费a一级| 精品成人在线 | 激情五月***国产精品 | 久久九九久久九九 | 九九九热精品免费视频观看网站 | 国产精品成人免费精品自在线观看 | 免费aa大片 | 欧美一级电影片 | 国产精品美女久久久久久久 | 一区二区影视 | 丁香婷婷综合色啪 | 久久亚洲综合色 | 日日爽日日操 | 欧美作爱视频 | av免费看网站 | 一区二区精品在线视频 | a天堂一码二码专区 | 人人看看人人 | 国产日韩欧美中文 | 黄色一级大片在线免费看国产一 | 手机在线永久免费观看av片 | 欧美日韩国产综合网 | av黄色成人| 激情伊人五月天久久综合 | 超碰在线公开免费 | 久久伊人精品天天 | 岛国一区在线 | 日韩免费电影一区二区三区 | 日韩一区二区在线免费观看 | 99久久精品国产一区二区成人 | 99re国产视频 | 久久久久婷 | 亚洲日本国产精品 | 国产91区| 亚洲精品国产免费 | 成人在线视频一区 | 日韩影视在线观看 | 2023av| 91av99| 成人精品影视 | 国产精品久久久久久久午夜片 | 国产一级特黄电影 | 99视屏| 国产视频精品久久 | 日韩动漫免费观看高清完整版在线观看 | 天天色天 | 国产日韩欧美综合在线 | 99久久精品网 | 色在线最新 | 国产精品久久久久久久久久尿 | 国产精品午夜8888 | 亚洲欧美激情精品一区二区 | 国产91精品一区二区 | 久久精品网址 | 国产麻豆精品传媒av国产下载 | 欧美日本一区 | 激情久久久久 | 亚洲精选在线观看 | 久久久网 | 色停停五月天 | 久久手机看片 | 九九久久免费 | 亚洲精品国精品久久99热 | 超碰在线亚洲 | 91成人在线看 | 精品国产乱码久久久久久天美 | 国产精品自产拍在线观看网站 | 91久久久久久久一区二区 | 98久久| 色国产精品一区在线观看 | 免费久久精品视频 | 六月丁香婷婷久久 | 国产精品色 | 色伊人网| 国产精品成人免费一区久久羞羞 | 婷婷亚洲最大 | 2019中文最近的2019中文在线 | 久久国产综合视频 | 99 精品 在线 | 香蕉视频在线看 | 国产黄色美女 | 91精品区 | 2021久久| 中文字幕人成不卡一区 | 香蕉视频啪啪 | 亚洲一区二区视频在线 | 国产三级精品在线 | 久久与婷婷 | 日韩在线观看电影 | 色综合中文综合网 | 中文字幕永久免费 | 国产视频在线观看一区 | 中文字幕资源在线观看 | 国产主播大尺度精品福利免费 | 高清色免费 | 欧美另类69 | av噜噜噜在线播放 | 97免费在线视频 | 日韩欧美电影在线观看 | 最新av观看 | 国产伦精品一区二区三区无广告 | 成人免费在线观看入口 | 日韩三级在线观看 | 成人性生交大片免费看中文网站 | 久久久久久高潮国产精品视 | 国产精品一码二码三码在线 | 午夜精品久久久久久久99 | 99在线热播精品免费 | 亚洲男模gay裸体gay | 久久成电影| 伊人天天狠天天添日日拍 | 欧美一级电影在线观看 | 一级黄色a视频 | 中文久久精品 | 韩国av在线播放 | 视频高清| 亚洲欧洲精品一区二区 | 久久久久久久久艹 | 97久久精品午夜一区二区 | 免费色黄 | 日韩视频一区二区 | 免费在线观看av网址 | 在线亚洲人成电影网站色www | www.com.日本一级| 久久久久国产精品厨房 | 中文久久精品 | 天天碰天天操视频 | 香蕉久久久久 | 2023国产精品自产拍在线观看 | 波多在线视频 | 99免在线观看免费视频高清 | 国产精品免费观看国产网曝瓜 | 99精彩视频在线观看免费 | 中文av字幕在线观看 | 免费看v片 | 夜色资源站wwwcom | 91av看片| 99精品系列 | 中文字幕在线观看免费高清电影 | 精品视频在线看 | 亚洲区视频在线 | 久久国语露脸国产精品电影 | 国产高清视频免费在线观看 | 极品久久久久 | 天天干天天拍天天操 | 麻豆精品在线 | 久久亚洲婷婷 | 国产精品自产拍 | 久久久久久蜜桃一区二区 | 欧美一级性生活片 | 久草在线视频在线观看 | 成人精品电影 | 91在线看视频 | 久久久久久久久久伊人 | 免费av片在线| 日韩电影中文,亚洲精品乱码 | 色婷婷www| 911久久香蕉国产线看观看 | 日韩精品一区二区三区免费观看视频 | 中文字幕高清免费日韩视频在线 | 亚洲国产日韩一区 | 99久久99久久精品国产片 | 亚洲国产精品500在线观看 | 久久久久久久精 | 亚洲人视频在线 | 久久精品导航 | 香蕉久久久久久av成人 | 亚洲一级片免费观看 | 国产高清视频免费观看 | 免费看毛片在线 | 超级碰视频 | 三级黄色片在线观看 | 欧美精品视| 伊人开心激情 | 成人黄色av免费在线观看 | 久久不卡国产精品一区二区 | 97超碰人人网| 在线观看成年人 | 久久99精品国产麻豆宅宅 | 看全黄大色黄大片 | 久久婷婷色 | 91精品国自产在线 | 国产在线久久久 | 欧美一区二区在线刺激视频 | 亚洲精品国偷自产在线99热 | 九月婷婷人人澡人人添人人爽 | 国产精品一区欧美 | 成人黄在线 | 懂色av一区二区三区蜜臀 | 日本精品va在线观看 | 色av色av色av | 亚洲精品大全 | 日韩精品免费一线在线观看 | 99产精品成人啪免费网站 | 亚洲高清视频在线播放 | 97超碰人人澡人人爱 | 中文字幕一区二区三区四区在线视频 | 玖玖视频国产 | 色综合婷婷久久 | 国产九九在线 | 夜夜夜夜夜夜操 | 国产h片在线观看 | 午夜电影久久 | 久99久在线| 黄色影院在线观看 | 亚洲一区二区天堂 | 视频国产在线观看18 | 精品欧美乱码久久久久久 | 日韩精品在线视频免费观看 | 日韩av电影一区 | 激情欧美一区二区三区免费看 | 国产精品18久久久久久不卡孕妇 | 香蕉视频免费在线播放 | 91在线中文 | 黄p在线播放 | 亚洲精品a区 | 美女视频国产 | 午夜精品久久久久久久久久久久 | www天天操 | 久草在线免费看视频 | 日韩经典一区二区三区 | 96国产精品| 久99久视频| 91亚色免费视频 | 国产免费三级在线观看 | 激情综合网色播五月 | 国产成人精品综合久久久 | 国产精品福利久久久 | 国产精品黄色在线观看 | 91精品爽啪蜜夜国产在线播放 | 中文字幕在线观看免费观看 | 99热亚洲精品 | 日韩在线视频网 | 成人黄色av网站 | 亚洲欧美综合精品久久成人 | 国产精品99久久久久久久久久久久 | 国产91成人在在线播放 | 激情综合五月 | 日韩精品观看 | 国产69熟 | 午夜久久久久久久久久影院 | 国产一区二区三区黄 | 日韩色在线 | 国产日韩欧美在线观看视频 | 99精品欧美一区二区三区 | 国外调教视频网站 | 四虎在线免费观看视频 | 91香蕉视频污在线 | 国产一区二区在线播放视频 |