青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

像打了激速一樣,以四倍的速度運轉,開心的工作
簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

鴨子-策略模式(Strategy) [轉]

Posted on 2009-01-27 16:22 S.l.e!ep.¢% 閱讀(718) 評論(1)  編輯 收藏 引用 所屬分類: Design Pattern

鴨子 - 策略模式( Strategy

前言

萬事開頭難,最近對這句話體會深刻!這篇文章是這個系列正式開始介紹設計模式的第一篇,所以肩負著確定這個系列風格的歷史重任,它在我腦袋里默默地醞釀了好多天,卻只搜刮出了一點兒不太清晰的輪廓,可是時間不等人,以后再多“迭代”幾次吧!在前面的隨筆里,我已經提到了,這個系列準備以《 Head First Design Patterns 》的結構為主線,所以每個模式的核心故事都是取材于此書,在此再次聲明一下。不管怎樣,宗旨是為了跟大家一起循序漸進地去認識設計模式。

上一篇:模式和原則,得到很多朋友的支持和鼓勵,這里再次深表感謝。這里我還是想呼吁一下,希望大家看過后多提寶貴意見,反對意見更好,關鍵是我們在互動中可以共同進步,因為經驗告訴我討論 ( 爭論更甚 ) 出來的火花,總是印象最深刻的。

其實策略模式是一個很簡單的模式,也是一個很常用的模式,可謂短小精悍。我在介紹這個模式的同時,為了加深大家對 OO 的理解,還會反復強調前面講過的設計原則和 GRASP 模式。這個系列的文章前后多少會有一些關聯的連續性,但是單獨一篇文章針對單一模式也一定是獨立的,所以不論大家想從前往后連續看也好,還是挑喜歡的跳著看,都沒有問題。

“羅嗦了這么多,太唐僧了吧,快點開始吧 ( 爛西紅柿和臭雞蛋從四面八方飛來 )

模擬鴨子

Joe 是一名 OO 程序員,他為一家開發模擬鴨子池塘游戲的公司工作,該公司的主要產品是一種可以模擬展示多種會游泳和呷呷叫的鴨子的游戲。這個游戲是使用標準的面向對象技術開發的,系統里所有鴨子都繼承于 Duck 基類 , 系統的核心類圖如下:

如圖所示,在 Duck 基類里實現了公共的 quack() swim() 方法,而 MallardDuck RedheadDuck 可以分別覆蓋實現自己的 display() 方法,這樣即重用了公共的部分,又支持不同子類的個性化擴展。從目前的情況看,這是一個很好的設計,哈! ??

但是,商場如戰場,不進則退。 Joe 的公司最近的日子不好過,盜版泛濫,再加上競爭對手的圍追堵劫,已經拖欠好幾個月工資了。因此,公司高層在一次集體“腐敗”后,決定一定要給系統增加一些超玄的功能,以徹底擊垮競爭對手。經過董事會討論,最終覺得如果能讓鴨子飛起來,那么一定可以給對手致命一擊。于是 Joe 的上司對董事們拍著胸脯說:“這沒有問題, Joe 是一個 OO 程序員,這對他來說太簡單了!我們保證一周內結束戰斗。”

接到任務的 Joe 絲毫不敢怠慢,研究了上級的指示以后,發現只要在 Duck 里增加一個 fly() 方法就可以搞定了,這樣所有繼承 Duck 的鴨子就都擁有了會飛的能力,哈!這回獎金有盼頭啦!改進后的系統類圖如下:


??? Joe的上司很高興,帶著新產品給董事們演示去了……??

……

Joe 的上司:“我正在給董事們演示你會飛的鴨子,但是怎么有很多橡皮鴨子也在四處亂飛呢?你在耍我嗎?你還想不想混啦?!” ( 此處省略粗話 100 )

Joe 被嚇壞了,到手的獎金泡湯了!冷靜下來的 Joe 發現,原來在 Duck 類里增加的方法,也同樣被繼承于 Duck RubberDuck 類繼承了,所以就有了會飛的橡皮鴨子,這是嚴重違反該系統“真實模擬各種鴨子”的原則的!那么該怎么辦呢? Joe 很郁悶!他突然想到:如果在 RubberDuck 類里把 fly() 方法重寫一下會如何?在 RubberDuck 類的 fly() 里讓橡皮鴨子什么都不做,不就一切 OK 了嗎!那以后再增加一個木頭鴨子呢?它不會飛也不會叫,那不是要再重寫 quack() fly() 方法,以后再增加其它特殊的鴨子都要這樣,這不是太麻煩了,而且也很混亂。

最終, Joe 認識到使用繼承不是辦法,因為他的上司通知他,董事會決定以后每 6 個月就會升級一次系統,以應對市場競爭,所以未來的變化會很頻繁,而且還不可預知。如果以后靠逐個類去判斷是否重寫了 quack() fly() 方法來應對變化,顯然混不下去!

Joe 這時很迷惑,為什么屢試不爽的繼承,在系統維護升級的時候,無法很好地支持重用呢?)

那么使用接口怎么樣?我可以把 fly() 方法放在接口里,只有那些會飛的鴨子才需要實現這個接口,最好把 quack() 方法也拿出來放到一個接口里,因為有些鴨子是不會叫的。就像下面這樣:



Joe 的上司知道后怒了:“你這樣做難道是希望所有需要 quack() fly() 方法的鴨子都去重復實現這兩個方法的功能嗎?就這么幾個鴨子還好說,但是我們有幾十、上百個鴨子的時候你怎么辦?如果某個方法要做一點修改,難道你要重復修改上百遍嗎?你是不是瘋啦?”

呵呵!如果你是 Joe ,你該怎么辦?

我們知道,并不是所有的鴨子都會飛、會叫,所以繼承不是正確的方法。但是雖然上面的使用 Flyable 接口的方法,可以解決部分問題 ( 不再有會飛的橡皮鴨子 ) ,但是這個解決方案卻徹底破壞了重用,它帶來了另一個維護的噩夢!而且還有一個問題我們前面沒有提到,難道所有的鴨子的飛行方式、叫聲等行為都是一模一樣的嗎?不可能吧!

說到這里,為了能幫助 Joe 擺脫困境,我們有必要先停下來,重新回顧一些面向對象設計原則。請您告訴我:“什么東西是在軟件開發過程中是恒定不變的?”,您想到了嗎?對,那就是變化本身,正所謂“計劃沒有變化快”,所以直面“變化這個事實”才是正道! Joe 面對的問題是,鴨子的行為在子類里持續不斷地改變,所以讓所有的子類都擁有基類的行為是不適當的,而使用上面的接口的方式,又破壞了代碼重用。現在就需要用到我們的第一個設計原則:

Identify the aspects of your application that vary and separate them from what stays the same. ( 找到系統中變化的部分,將變化的部分同其它穩定的部分隔開。 )

換句話說就是:“找到變化并且把它封裝起來,稍后你就可以在不影響其它部分的情況下修改或擴展被封裝的變化部分。” 盡管這個概念很簡單,但是它幾乎是所有設計模式的基礎,所有模式都提供了使系統里變化的部分獨立于其它部分的方法。

OK !現在我們已經有了一條設計原則,那么 Joe 的問題怎么辦呢?就鴨子的問題來說,變化的部分就是子類里的行為。所以我們要把這部分行為封裝起來,省得它們老惹麻煩!從目前的情況看,就是 fly() quack() 行為總是不老實,而 swim() 行為是很穩定的,這個行為是可以使用繼承來實現代碼重用的,所以,我們需要做的就是把 fly() quack() 行為從 Duck 基類里隔離出來。我們需要創建兩組不同的行為,一組表示 fly() 行為,一組表示 quack() 行為。為什么是兩組而不是兩個呢?因為對于不同的子類來說, fly() quack() 的表現形式都是不一樣的,有的鴨子嘎嘎叫,有的卻呷呷叫。有了這兩組行為,我們就可以組合出不同的鴨子,例如:我們可能想要實例化一個新的 MallardDuck( 野鴨 ) 實例,并且給它初始化一個特殊類型的飛行行為 ( 野鴨飛行能力比較強 ) 。那么,如果我們可以這樣,更進一步,為什么我們不可以動態地改變一個鴨子的行為呢?換句話說,我們將在 Duck 類里包含行為設置方法,所以我們可以說在運行時改變 MallardDuck 的飛行行為,這聽起來更酷更靈活了!那么我們到底要怎么做呢?回答這個問題,先要看一下我們的第二個設計原則:

Program to an interface, not an implementation. (面向接口編程,而不要面向實現編程。)

嘿!對于這個原則,不論是耳朵還是眼睛,是不是都太熟悉了!“接口”這個詞已經被賦予太多的含義,搞的大家一說點兒屁事就滿嘴往外蹦“接口”。那么它到底是什么意思呢?我們這里說的接口是一個抽象的概念,不局限于語言層面的接口 ( 例如 C# 里的 interface) 。一個接口也可以是一個抽象類,或者一個基類也可以看作是一種接口的表現形式,因為基類變量可以用來引用其子類。要點在于,我們在面向接口編程的時候,可以使用多態,那么實際運行的代碼只依賴于具體的接口 (interface, 抽象類,基類 ) ,而不管這些接口提供的功能是如何實現的,也就是說,接口將系統的不同部分隔離開來,同時又將它們連接在一起。我的神啊!接口真是太偉大了! ( 爛西紅柿和臭雞蛋從四面八方飛來 )

OK! 這回該徹底解決 Joe 的問題了!

根據面向接口編程的設計原則,我們應該用接口來隔離鴨子問題中變化的部分,也就是鴨子的不穩定的行為 (fly() quack()) 。我們要用一個 FlyBehavior 接口表示鴨子的飛行行為,這個接口可以有多種不同的實現方式,可以“橫”著分,也可以“豎”著分,管它呢!這樣做的好處就是我們將鴨子的行為實現在一組獨立的類里,具體的鴨子是通過 FlyBehavior 這個接口來調用這個行為的,因為 Duck 只依賴 FlyBehavior 接口,所以不需要管 FlyBehavior 是如何被實現的。如下面的類圖, FlyBehavior QuackBehavior 接口都有不同的實現方式!

Joe 已經暈了,“你說了這么多,全是大白話,來點代碼行不行,我要 C# 的!”。說到這里,我們也該開始徹底改造這個設計了,并會在最后附加部分代碼來幫助大家理解。??

第一步:我們要給 Duck 類增加兩個接口類型的實例變量,分別是 flyBehavior quackBehavior ,它們其實就是新的設計里的“飛行”和“叫喚”行為。每個鴨子對象都將會使用各種方式來設置這些變量,以引用它們期望的運行時的特殊行為類型 ( 使用橫著飛,吱吱叫,等等 )

第二步:我們還要把 fly() quack() 方法從 Duck 類里移除,因為我們已經把這些行為移到 FlyBehavior QuackBehavior 接口里了。我們將使用兩個相似的 PerformFly() PerformQuack() 方法來替換 fly() qucak() 方法,后面你會看到這兩個新方法是如何起作用的。

第三步:我們要考慮什么時候初始化 flyBehavior quackBehavior 變量。最簡單的辦法就是在 Duck 類初始化的時候同時初始化他們。但是我們這里還有更好的辦法,就是提供兩個可以動態設置變量值的方法 SetFlyBehavior() SetQuackBehavior() ,那么就可以在運行時動態改變鴨子的行為了。

下面是修改后的 Duck 類圖:

我們再看看整個設計修改后的類圖:


最后大家再看看演示代碼,因為代碼比較多,就不貼出來了,大家可以下載后參考:。下面是演示代碼的執行結果:


這就是策略模式

前面說了那么多,現在終于到了正式介紹我們今天的主角的時候啦!此刻心情真是好激動啊!其實我們在前面就是使用 Strategy 模式幫 Joe 度過了難過,真不知道他發了獎金后要怎么感謝我們啊。 OK !下面先看看官方的定義:

The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. (策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法獨立于使用它的客戶而獨立變化。)

怎么樣,有了前面 Joe 的經歷,這個定義理解起來還不那么太費勁吧?我想凡是認真看到這里的人,應該都能理解的。那么下面再畫蛇添足地羅嗦幾句,給那些還不太理解的朋友一個機會吧。 J

Context( 應用場景 ):

l???????? 需要使用 ConcreteStrategy 提供的算法。

l???????? 內部維護一個 Strategy 的實例。

l???????? 負責動態設置運行時 Strategy 具體的實現算法。

l???????? 負責跟 Strategy 之間的交互和數據傳遞。

Strategy( 抽象策略類 )

l???????? 定義了一個公共接口,各種不同的算法以不同的方式實現這個接口, Context 使用這個接口調用不同的算法,一般使用接口或抽象類實現。

ConcreteStrategy( 具體策略類 )

l???????? 實現了 Strategy 定義的接口,提供具體的算法實現。

?

還不理解?!我的神啊!那再看看下面的順序圖吧,這是最后的機會啦!


應用場景和優缺點

上面我們已經看過了 Strategy 模式的詳細介紹,下面我們再來簡單說說這個模式的優缺點吧!怎么說呢,人無完人,設計模式也不是萬能的,每一個模式都有它的使命,也就是說只有在特定的場景下才能發揮其功效。我們要使用好模式,就必須熟知各個模式的應用場景。

對于 Strategy 模式來說,主要有這些應用場景:

1、? 多個類只區別在表現行為不同,可以使用 Strategy 模式,在運行時動態選擇具體要執行的行為。 ( 例如 FlyBehavior QuackBehavior)

2、? 需要在不同情況下使用不同的策略 ( 算法 ) ,或者策略還可能在未來用其它方式來實現。 ( 例如 FlyBehavior QuackBehavior 的具體實現可任意變化或擴充 )

3、? 對客戶 (Duck) 隱藏具體策略 ( 算法 ) 的實現細節,彼此完全獨立。

?

對于 Strategy 模式來說,主要有如下優點:

1、? 提供了一種替代繼承的方法,而且既保持了繼承的優點 ( 代碼重用 ) 還比繼承更靈活 ( 算法獨立,可以任意擴展 )

2、? 避免程序中使用多重條件轉移語句,使系統更靈活,并易于擴展。

3、? 遵守大部分 GRASP 原則和常用設計原則,高內聚、低偶合。

對于 Strategy 模式來說,主要有如下缺點:

1、? 因為每個具體策略類都會產生一個新類,所以會增加系統需要維護的類的數量。

?

??? 備注:關于場景和優缺點,上面肯定說得不夠全面,歡迎大家來補充。

.NET 框架里的應用

Strategy 模式的應用非常廣泛,也許大家有意無意之間一直都在使用。這里舉一個 .NET 框架里使用 Strategy 模式的例子,象這樣的例子其實還有很多,只要大家細心體會就一定會發現的。

如果寫過程序,那么 ArrayList 類肯定都會用過吧,那么它的 Sort 方法想必大家也一定不陌生了。 Sort 方法的定義如下:

public virtual void Sort (IComparercomparer)

可以看到 Sort 方法接收一個 IComparer 類型的參數,那么這個 IComparer 接口是做什么用的呢?下面我們看一段程序, 下面的代碼示例演示如何使用默認比較器和一個反轉排序順序的自定義比較器,對 ArrayList中的值進行排序。(完全引自MSDN ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref2/html/M_System_Collections_ArrayList_Sort_1_a2d90598.htm )

?

?1 using ?System;
?2 using ?System.Collections;
?3
?4 public ? class ?SamplesArrayList?? {
?5 ?
?6 ??? public ? class ?myReverserClass?:?IComparer?? {
?7
?8 ?????? // ?Calls?CaseInsensitiveComparer.Compare?with?the?parameters?reversed.
?9 ?????? int ?IComparer.Compare(?Object?x,?Object?y?)?? {
10 ?????????? return (?( new ?CaseInsensitiveComparer()).Compare(?y,?x?)?);
11 ??????}

12
13 ???}

14
15 ??? public ? static ? void ?Main()?? {
16 ?
17 ?????? // ?Creates?and?initializes?a?new?ArrayList.
18 ??????ArrayList?myAL? = ? new ?ArrayList();
19 ??????myAL.Add(? " The " ?);
20 ??????myAL.Add(? " quick " ?);
21 ??????myAL.Add(? " brown " ?);
22 ??????myAL.Add(? " fox " ?);
23 ??????myAL.Add(? " jumps " ?);
24 ??????myAL.Add(? " over " ?);
25 ??????myAL.Add(? " the " ?);
26 ??????myAL.Add(? " lazy " ?);
27 ??????myAL.Add(? " dog " ?);
28 ?
29 ?????? // ?Displays?the?values?of?the?ArrayList.
30 ??????Console.WriteLine(? " The?ArrayList?initially?contains?the?following?values: " ?);
31 ??????PrintIndexAndValues(?myAL?);
32 ?
33 ?????? // ?Sorts?the?values?of?the?ArrayList?using?the?default?comparer.
34 ??????myAL.Sort();
35 ??????Console.WriteLine(? " After?sorting?with?the?default?comparer: " ?);
36 ??????PrintIndexAndValues(?myAL?);
37
38 ?????? // ?Sorts?the?values?of?the?ArrayList?using?the?reverse?case-insensitive?comparer.
39 ??????IComparer?myComparer? = ? new ?myReverserClass();
40 ??????myAL.Sort(?myComparer?);
41 ??????Console.WriteLine(? " After?sorting?with?the?reverse?case-insensitive?comparer: " ?);
42 ??????PrintIndexAndValues(?myAL?);
43
44 ???}

45 ?
46 ??? public ? static ? void ?PrintIndexAndValues(?IEnumerable?myList?)?? {
47 ?????? int ?i? = ? 0 ;
48 ?????? foreach ?(?Object?obj? in ?myList?)
49 ?????????Console.WriteLine(? " \t[{0}]:\t{1} " ,?i ++ ,?obj?);
50 ??????Console.WriteLine();
51 ???}

52
53 }

54
55
56 /* ?
57 This?code?produces?the?following?output.
58 The?ArrayList?initially?contains?the?following?values:
59 ????????[0]:????The
60 ????????[1]:????quick
61 ????????[2]:????brown
62 ????????[3]:????fox
63 ????????[4]:????jumps
64 ????????[5]:????over
65 ????????[6]:????the
66 ????????[7]:????lazy
67 ????????[8]:????dog
68
69 After?sorting?with?the?default?comparer:
70 ????????[0]:????brown
71 ????????[1]:????dog
72 ????????[2]:????fox
73 ????????[3]:????jumps
74 ????????[4]:????lazy
75 ????????[5]:????over
76 ????????[6]:????quick
77 ????????[7]:????the
78 ????????[8]:????The
79
80 After?sorting?with?the?reverse?case-insensitive?comparer:
81 ????????[0]:????the
82 ????????[1]:????The
83 ????????[2]:????quick
84 ????????[3]:????over
85 ????????[4]:????lazy
86 ????????[5]:????jumps
87 ????????[6]:????fox
88 ????????[7]:????dog
89 ????????[8]:????brown?
90 */

?

怎么樣,大家看出來了吧,其實在這段代碼里, ArrayList 相當于 Strategy 模式中的 Context( 應用場景 ) 部分,而 IComparer 相當于 Strategy( 抽象 策略類 ) 部分, myReverserClass 相當于 ConcreteStrategy( 具體 策略類 ) 部分。我們這里拋開 myReverserClass 類的 Compare 方法 如何具體實現不談,我們只要知道這是一個具體 策略類,它提供了應用場景需要的具體算法,它實現了抽象策略類接口,而應用場景通過 抽象 策略類動態調用到了 具體 策略類中的算法 。哈!所以這是一個十分典型的 Strategy 模式的應用。

基于這個符合 Strategy 模式的結構,我們還可以提供很多種自定義的具體 策略類的實現,只要這些類實現了 IComparer 接口,就可以在運行時動態設置給 ArrayList 類的 Sort 方法,在 Sort 方法中會根據具體 策略類實現的比較算法規則來對 ArrayList 中的數據進行排序。

最后一個設計原則

關于 Strategy 模式的故事講到這里,應該基本 OK 啦!下面我們再聊些更高層次的東西。什么是更高層次的東西?嘿!當然是設計原則了!在前面總結 Strategy 模式的優點的時候我們提到過, Strategy 模式不僅保留了繼承的優點,而且還提供了更靈活的擴展能力。為什么會這樣呢? Strategy 模式是怎么做到這一點的呢?哈!這是因為它“上面有人”啊!誰啊?它就是我們下面要介紹的重量級設計原則:

Favor composition over inheritance. (優先使用對象組合,而非類繼承)

關于組合和繼承,我們只要這樣來理解即可:組合是一種“ HAS-A ”關系,而繼承是一種“ IS-A ”關系。很明顯“ HAS-A ”要比“ IS-A ”更靈活一些。也就是說在創建系統的時候,我們應該優先使用對象組合,因為它不僅可以給你提供更多靈活性和擴展性,而且還使你可以在運行時改變行為 ( 組合不同的對象 ) ,這簡直是酷斃了!但是也不是說繼承就是不能用,只是說應該把繼承應用在相對更穩定,幾乎沒有變化的地方,例如前面的 Duck 類里的 Swim() 方法,因為可以肯定所有鴨子一定都會游泳,所以就沒有必要給這個行為提供基于 Strategy 模式的實現方式,因為那樣做除了是程序更復雜以外,沒有什么意義。

BULLET POINTS

l??????? Knowing the OO basics does not make you a good OO designer.

l??????? Good OO designs are reusable,extensible and maintainable.

l??????? Patterns show you how to build systems with good OO design qualities.

l??????? Patterns are proven object oriented experience.

l??????? Patterns don’t give you code,they give you general solutions to design problems.You apply them to your specific application.

l??????? Patterns aren’t invented,they are discovered.

l??????? Most patterns and principles address issues of change in software.

l??????? Most patterns allow some part of a system to vary independently of all other parts.

l??????? We often try to take what varies in a system and encapsulate it.

l??????? Patterns provide a shared language that can maximize the value of your communication with other developers.

作者

王曉亮 /Justin

MSN:xiaoliang203@hotmail.com

Mail:xiaoliang.justin@gmail.com

參考資料

UML 和模式應用》

《敏捷軟件開發—原則、模式與實踐》

Head First Design Patterns

李建忠 老師的《 C# 面向對象設計模式縱橫談系列課程》

Feedback

# re: 鴨子-策略模式(Strategy) [轉]  回復  更多評論   

2009-01-28 17:31 by 陳梓瀚(vczh)
使用C++的多重繼承,則能輕松解決,用不著那么多behavior。
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲美女黄色| 午夜精品久久久久久99热| 六月天综合网| 久久久久久久97| 久久亚洲一区二区三区四区| 久久手机免费观看| 欧美a级片网站| 欧美日韩国产在线观看| 欧美色精品在线视频| 国产精品日日做人人爱| 狠狠入ady亚洲精品经典电影| 国产一区二区精品| 亚洲欧洲精品一区二区| 亚洲一区美女视频在线观看免费| 性感少妇一区| 欧美福利视频在线| 在线亚洲成人| 久久人体大胆视频| 国产精品久久久久一区| 一区二区三区在线免费观看| 99精品免费网| 久久婷婷综合激情| 一区二区三区四区五区精品| 亚洲性感美女99在线| 亚洲精品一区二区三区蜜桃久| 欧美日韩国产区| 欧美二区乱c少妇| 亚洲精品欧美| 久久精品一区中文字幕| 欧美精品一区二区蜜臀亚洲| 国产欧美日韩综合一区在线播放| 亚洲国产日韩一区二区| 欧美一区国产在线| 亚洲人妖在线| 亚洲男人av电影| 欧美精品精品一区| 娇妻被交换粗又大又硬视频欧美| 亚洲一区二区三区免费在线观看 | 日韩一级成人av| 久久精品视频免费| 国产精品一二三四| 中文av字幕一区| 亚洲成人中文| 久久久久久亚洲精品不卡4k岛国| 国产精品每日更新| 亚洲在线观看视频网站| 亚洲精品国精品久久99热| 久久综合久久美利坚合众国| 国产亚洲毛片在线| 欧美在线观看网站| 亚洲伊人一本大道中文字幕| 欧美日本一道本| 亚洲精品在线三区| 亚洲国产成人高清精品| 狼人社综合社区| 亚洲国产精品va| 欧美电影资源| 欧美好吊妞视频| 99精品视频免费观看| 亚洲欧洲一二三| 欧美日本一区二区三区| 亚洲视频香蕉人妖| 亚洲性线免费观看视频成熟| 国产精品久久久久久久久| 亚洲永久在线| 亚洲欧美日韩国产中文在线| 国产精品午夜在线观看| 久久成人18免费网站| 欧美一区二区三区视频免费| 国内偷自视频区视频综合| 老妇喷水一区二区三区| 噜噜噜躁狠狠躁狠狠精品视频| 亚洲电影自拍| 亚洲精品日产精品乱码不卡| 国产精品第三页| 欧美在线视屏| 久久一二三国产| 日韩视频一区二区三区| 一本一本久久| 国产一区二区三区不卡在线观看| 亚洲摸下面视频| 模特精品在线| 夜夜嗨av色综合久久久综合网| 91久久国产自产拍夜夜嗨| 欧美性猛交视频| 欧美在线影院| 欧美777四色影视在线| 亚洲婷婷在线| 欧美在线免费| 亚洲美洲欧洲综合国产一区| 中文在线资源观看网站视频免费不卡| 国产视频一区在线观看| 欧美激情第六页| 国产精品视频专区| 欧美国产精品| 国产精品综合av一区二区国产馆| 久久性色av| 欧美日韩在线亚洲一区蜜芽| 久久久www成人免费毛片麻豆| 欧美成人首页| 久久久噜噜噜久久久| 欧美黄色免费网站| 久久精品视频一| 欧美日韩日日夜夜| 欧美a级一区| 国产精品自拍视频| 亚洲毛片一区| 亚洲国产精品ⅴa在线观看| 亚洲天堂av高清| 亚洲美女精品成人在线视频| 久久国产精品久久w女人spa| 亚洲主播在线播放| 欧美激情乱人伦| 美女在线一区二区| 国产欧美精品一区二区色综合| 亚洲精品日韩在线观看| 亚洲电影第三页| 久久国产综合精品| 欧美在线观看你懂的| 国产精品久久福利| 日韩亚洲欧美一区二区三区| 亚洲欧洲日产国产网站| 久久久久网址| 久久久久久国产精品mv| 国产区精品视频| 亚洲在线成人| 亚洲欧美日韩国产一区二区| 欧美日韩国产成人在线观看| 亚洲国产精品一区二区三区| 揄拍成人国产精品视频| 欧美中文字幕在线播放| 欧美在线视频a| 国产情人节一区| 欧美一区二区播放| 欧美一区二区视频在线观看2020 | 亚洲三级免费| 蜜桃久久av一区| 欧美国产大片| 亚洲精品乱码久久久久久日本蜜臀| 久久久久.com| 欧美77777| 亚洲欧洲日本国产| 欧美中文字幕视频在线观看| 欧美日韩高清在线播放| 先锋影音一区二区三区| 国产精品影片在线观看| 午夜精品久久久久| 久久国产手机看片| 国内精品美女av在线播放| 久久精品首页| 欧美国产免费| 一区二区欧美在线观看| 欧美三区美女| 亚洲欧美高清| 久久久久九九视频| 91久久国产综合久久91精品网站| 欧美va亚洲va香蕉在线| 亚洲精品一区二区三区蜜桃久 | 久久久国产精品一区二区中文| 国产主播一区| 免费久久精品视频| 一区二区三区|亚洲午夜| 午夜精品免费在线| 影音先锋久久资源网| 欧美日韩国产探花| 午夜精品一区二区三区四区| 欧美91福利在线观看| 一区二区三区免费网站| 国产免费亚洲高清| 欧美成年人视频网站| 亚洲一二三区精品| 欧美激情视频在线播放| 亚洲一区二区三区在线观看视频 | 国产视频观看一区| 欧美国产激情| 亚洲欧美日韩国产另类专区| 欧美成人中文字幕| 亚洲欧美日韩国产一区| 亚洲丰满在线| 国产精品久久亚洲7777| 久久三级福利| 亚洲一级二级| 亚洲国产婷婷| 久久大香伊蕉在人线观看热2| 亚洲欧洲精品一区二区三区不卡 | 久久免费高清视频| 这里只有精品电影| 亚洲第一网站免费视频| 欧美一区二区在线免费观看| 99综合在线| 在线电影国产精品| 国产欧美精品va在线观看| 欧美日韩亚洲不卡| 免费观看成人网| 欧美专区在线播放| 亚洲欧美激情视频| 日韩亚洲欧美成人一区| 亚洲国产欧美一区| 欧美成人精品在线观看| 久久激情综合网|