国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁(yè) > 編程 > Ruby > 正文

Ruby設(shè)計(jì)模式編程之適配器模式實(shí)戰(zhàn)攻略

2020-10-29 19:36:22
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

適配器模式
適配器模式可以用于對(duì)不同的接口進(jìn)行包裝以及提供統(tǒng)一的接口,或者是讓某一個(gè)對(duì)象看起來(lái)像是另一個(gè)類(lèi)型的對(duì)象。在靜態(tài)類(lèi)型的編程語(yǔ)言里,我們經(jīng)常使用它去滿(mǎn)足類(lèi)型系統(tǒng)的特點(diǎn),但是在類(lèi)似Ruby這樣的弱類(lèi)型編程語(yǔ)言里,我們并不需要這么做。盡管如此,它對(duì)于我們來(lái)說(shuō)還是有很多意義的。
當(dāng)使用第三方類(lèi)或者庫(kù)的時(shí)候,我們經(jīng)常從這個(gè)例子開(kāi)始(start out fine):

def find_nearest_restaurant(locator) locator.nearest(:restaurant, self.lat, self.lon)end

我們假設(shè)有一個(gè)針對(duì)locator的接口,但是如果我們想要find_nearest_restaurant能夠支持另一個(gè)庫(kù)呢?這個(gè)時(shí)候我們可能就會(huì)去嘗試添加新的特殊的場(chǎng)景的處理:

def find_nearest_restaurant(locator) if locator.is_a? GeoFish  locator.nearest(:restaurant, self.lat, self.lon) elsif locator.is_a? ActsAsFound  locator.find_food(:lat => self.lat, :lon => self.lon) else  raise NotImplementedError, "#{locator.class.name} is not supported." endend

這是一個(gè)比較務(wù)實(shí)的解決方案。或許我們也不再需要考慮去支持另一個(gè)庫(kù)了。也或許find_nearest_restaurant就是我們使用locator的唯一場(chǎng)景。
那假如你真的需要去支持一個(gè)新的locator,那又會(huì)是怎么樣的呢?那就是你有三個(gè)特定的場(chǎng)景。再假如你需要實(shí)現(xiàn)find_nearest_hospital方法呢?這樣你就需要在維護(hù)這三種特定的場(chǎng)景時(shí)去兼顧兩個(gè)不同的地方。當(dāng)你覺(jué)得這種解決方案不再可行的時(shí)候,你就需要考慮適配器模式了。
在這個(gè)例子中,我們可以為GeoFish以及ActsAsFound編寫(xiě)適配器,這樣的話(huà),在我們的其他代碼中,我們就不需要了解我們當(dāng)前正在使用的是哪個(gè)庫(kù)了:

def find_nearest_hospital(locator) locator.find :type => :hospital,        :lat => self.lat,        :lon => self.lonendlocator = GeoFishAdapter.new(geo_fish_locator)find_nearest_hospital(locator)

特意假設(shè)的例子就到此為止,接下來(lái)讓我們看看真實(shí)的代碼。

實(shí)例
今天一大早,你的leader就匆匆忙忙跑過(guò)來(lái)找到你:“快,快,緊急任務(wù)!最近ChinaJoy馬上就要開(kāi)始了,老板要求提供一種直觀的方式,可以查看到我們新上線的游戲中每個(gè)服的在線人數(shù)。”
你看了看日期,不是吧!這哪里是馬上要開(kāi)始了,分明是已經(jīng)開(kāi)始了!這怎么可能來(lái)得及呢?
“沒(méi)關(guān)系的。”你的leader安慰你道:“功能其實(shí)很簡(jiǎn)單的,接口都已經(jīng)提供好了,你只需要調(diào)用一下就行了。”
好吧,你勉為其難地接受了,對(duì)于這種突如其來(lái)的新需求,你早已習(xí)慣。
你的leader向你具體描述了一下需求,你們的游戲目前有三個(gè)服,一服已經(jīng)開(kāi)放一段時(shí)間了,二服和三服都是新開(kāi)的服。設(shè)計(jì)的接口非常輕便,你只需要調(diào)用Utility.online_player_count(Fixnum),傳入每個(gè)服對(duì)應(yīng)的數(shù)值就可以獲取到相應(yīng)服在線玩家的數(shù)量了,如一服傳入1,二服傳入2,三服則傳入3。如果你傳入了一個(gè)不存在的服,則會(huì)返回-1。然后你只要將得到的數(shù)據(jù)拼裝成XML就好,具體的顯示功能由你的leader來(lái)完成。
好吧,聽(tīng)起來(lái)功能并不是很復(fù)雜,如果現(xiàn)在就開(kāi)始動(dòng)工好像還來(lái)得及,于是你馬上敲起了代碼。
首先定義一個(gè)用于統(tǒng)計(jì)在線人數(shù)的父類(lèi)PlayerCount,代碼如下:

class PlayerCount    def server_name     raise "You should override this method in subclass."   end      def player_count     raise "You should override this method in subclass."   end  end 

接著定義三個(gè)統(tǒng)計(jì)類(lèi)繼承PlayerCount,分別對(duì)應(yīng)了三個(gè)不同的服,如下所示:

class ServerOne < PlayerCount    def server_name     "一服"   end      def player_count     Utility.online_player_count(1)   end  end class ServerTwo < PlayerCount    def server_name     "二服"   end      def player_count     Utility.online_player_count(2)   end  end class ServerThree < PlayerCount    def server_name     "三服"   end      def player_count     Utility.online_player_count(3)   end  end 

然后定義一個(gè)XMLBuilder類(lèi),用于將各服的數(shù)據(jù)封裝成XML格式,代碼如下:

class XMLBuilder    def self.build_xml player     builder = ""     builder << "<root>"     builder << "<server>" << player.server_name << "</server>"     builder << "<player_count>" << player.player_count.to_s << "</player_count>"     builder << "</root>"   end  end 

這樣的話(huà),所有代碼就完工了,如果你想查看一服在線玩家數(shù)只需要調(diào)用:

XMLBuilder.build_xml(ServerOne.new) 

查看二服在線玩家數(shù)只需要調(diào)用:

XMLBuilder.build_xml(ServerTwo.new) 

查看三服在線玩家數(shù)只需要調(diào)用:

XMLBuilder.build_xml(ServerThree.new) 

咦?你發(fā)現(xiàn)查看一服在線玩家數(shù)的時(shí)候,返回值永遠(yuǎn)是-1,查看二服和三服都很正常。
你只好把你的leader叫了過(guò)來(lái):“我感覺(jué)我寫(xiě)的代碼沒(méi)有問(wèn)題,但是查詢(xún)一服在線玩家數(shù)總是返回-1,為什么會(huì)這樣呢?”
“哎呀!”你的leader猛然想起,“這是我的問(wèn)題,前面沒(méi)跟你解釋清楚。由于我們的一服已經(jīng)開(kāi)放一段時(shí)間了,查詢(xún)?cè)诰€玩家數(shù)量的功能早就有了,使用的是ServerFirst這個(gè)類(lèi)。當(dāng)時(shí)寫(xiě)Utility.online_player_count()這個(gè)方法主要是為了針對(duì)新開(kāi)的二服和三服,就沒(méi)把一服的查詢(xún)功能再重復(fù)做一遍。這種情況下可以使用適配器模式,這個(gè)模式就是為了解決接口之間不兼容的問(wèn)題而出現(xiàn)的。”
其實(shí)適配器模式的使用非常簡(jiǎn)單,核心思想就是只要能讓兩個(gè)互不兼容的接口能正常對(duì)接就行了。上面的代碼中,XMLBuilder中使用PlayerCount來(lái)拼裝XML,而ServerFirst并沒(méi)有繼承PlayerCount,這個(gè)時(shí)候就需要一個(gè)適配器類(lèi)來(lái)為XMLBuilder和ServerFirst之間搭起一座橋梁,毫無(wú)疑問(wèn),ServerOne就將充當(dāng)適配器類(lèi)的角色。修改ServerOne的代碼,如下所示:

class ServerOne < PlayerCount    def initialize     @serverFirst = ServerFirst.new   end    def server_name     "一服"   end      def player_count     @serverFirst.online_player_count   end  end 

 
這樣通過(guò)ServerOne的適配,XMLBuilder和ServerFirst之間就成功完成對(duì)接了!使用的時(shí)候我們甚至無(wú)需知道有ServerFirst這個(gè)類(lèi),只需要正常創(chuàng)建ServerOne的實(shí)例就行了。
需要值得注意的一點(diǎn)是,適配器模式不并是那種會(huì)讓架構(gòu)變得更合理的模式,更多的時(shí)候它只是充當(dāng)救火隊(duì)員的角色,幫助解決由于前期架構(gòu)設(shè)計(jì)不合理導(dǎo)致的接口不匹配的問(wèn)題。更好的做法是在設(shè)計(jì)的時(shí)候就盡量把以后可能出現(xiàn)的情況多考慮一些,在這個(gè)問(wèn)題上不要向你的leader學(xué)習(xí)。

MultiJSON
ActiveSupport在做JSON格式的解碼時(shí),用到的是MultiJSON,這是一個(gè)針對(duì)JSON庫(kù)的適配器。每一個(gè)庫(kù)都能夠解析JSON,但是做法卻不盡相同。讓我們分別看看針對(duì)oj和yajl的適配器。 (提示: 可在命令行中輸入qw multi_json查看源碼。)

module MultiJson module Adapters  class Oj < Adapter   #...   def load(string, options={})    options[:symbol_keys] = options.delete(:symbolize_keys)    ::Oj.load(string, options)   end   #...

Oj的適配器修改了options哈希表,使用Hash#delete將:symbolize_keys項(xiàng)轉(zhuǎn)換為Oj的:symbol_keys項(xiàng):

options = {:symbolize_keys => true}options[:symbol_keys] = options.delete(:symbolize_keys) # => trueoptions                         # => {:symbol_keys=>true}

接下來(lái)MultiJSON調(diào)用了::Oj.load(string, options)。MultiJSON適配后的API跟Oj原有的API非常相似,在此不必贅述。不過(guò)你是否注意到,Oj是如何引用的呢?::Oj引用了頂層的Oj類(lèi),而不是MultiJson::Adapters::Oj。
現(xiàn)在讓我們看看MultiJSON又是如何適配Yajl庫(kù)的:

module MultiJson module Adapters  class Yajl < Adapter   #...   def load(string, options={})    ::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string)   end   #...

這個(gè)適配器從不同的方式實(shí)現(xiàn)了load方法。Yajl的方式是先創(chuàng)建一個(gè)解析器的實(shí)力,然后將傳入的字符串string作為參數(shù)調(diào)用Yajl::Parser#parse方法。在options哈希表上的處理也略有不同。只有:symbolize_keys項(xiàng)被傳遞給了Yajl。
這些JSON的適配器看似微不足道,但是他們卻可以讓你隨心所欲地在不同的庫(kù)之間進(jìn)行切換,而不需要在每一個(gè)解析JSON的地方更新代碼。
ActiveRecord
很多JSON庫(kù)往往都遵從相似的模式,這讓適配工作變得相當(dāng)輕松。但是如果你是在處理一些更加復(fù)雜的情況時(shí),結(jié)果會(huì)是怎樣?ActiveRecord包含了針對(duì)不同數(shù)據(jù)庫(kù)的適配器。盡管PostgreSQL和MySQL都是SQL數(shù)據(jù)庫(kù),但是他們之間還是有很多不同之處,而ActiveRecord通過(guò)使用適配器模式屏蔽了這些不同。(提示: 命令行中輸入qw activerecord查看ActiveRecord的代碼)
打開(kāi)ActiveRecord代碼庫(kù)中的lib/connection_adapters目錄,里邊會(huì)有針對(duì)PostgreSQL,MySQL以及SQLite的適配器。除此之外,還有一個(gè)名為AbstractAdapter的適配器,它作為每一個(gè)具體的適配器的基類(lèi)。AbstractAdapter實(shí)現(xiàn)了在大部分?jǐn)?shù)據(jù)庫(kù)中常見(jiàn)的功能,這些功能在其子類(lèi)比如PostgreSQLAdapter以及AbstractMysqlAdapter中被重新定制,而其中AbstractMysqlAdapter則是另外兩個(gè)不同的MySQL適配器――MysqlAdapter以及Mysql2Adapter――的父類(lèi)。讓我們通過(guò)一些真實(shí)世界中的例子來(lái)看看他們是如何一起工作的。
PostgreSQL和MySQL在SQL方言的實(shí)現(xiàn)稍有不同。查詢(xún)語(yǔ)句SELECT * FROM users在這兩個(gè)數(shù)據(jù)庫(kù)都可以正常執(zhí)行,但是它們?cè)谝恍╊?lèi)型的處理上會(huì)稍顯不同。在MySQL和PostgreSQL中,時(shí)間格式就不盡相同。其中,PostgreSQL支持微秒級(jí)別的時(shí)間,而MySQL只是到了最近的一個(gè)穩(wěn)定發(fā)布的版本中才支持。那這兩個(gè)適配器又是如何處理這種差異的呢?
ActiveRecord通過(guò)被混入到AbstractAdapter的ActiveRecord::ConnectionAdapters::Quoting中的quoted_date引用日期。而AbstractAdapter中的實(shí)現(xiàn)僅僅只是格式化了日期:

def quoted_date(value) #... value.to_s(:db)end

Rails中的ActiveSupport擴(kuò)展了Time#to_s,使其能夠接收一個(gè)代表格式名的符號(hào)類(lèi)型參數(shù)。:db所代表的格式就是%Y-%m-%d %H:%M:%S:

# Examples of common formats:Time.now.to_s(:db)   #=> "2014-02-19 06:08:13"Time.now.to_s(:short)  #=> "19 Feb 06:08"Time.now.to_s(:rfc822) #=> "Wed, 19 Feb 2014 06:08:13 +0000"

MySQL的適配器都沒(méi)有重寫(xiě)quoted_date方法,它們自然會(huì)繼承這種行為。另一邊,PostgreSQLAdapter則對(duì)日期的處理做了兩個(gè)修改:

def quoted_date(value) result = super if value.acts_like?(:time) && value.respond_to?(:usec)  result = "#{result}.#{sprintf("%06d", value.usec)}" end if value.year < 0  result = result.sub(/^-/, "") + " BC" end resultend

它在一開(kāi)始便調(diào)用super方法,所以它也會(huì)得到一個(gè)類(lèi)似MySQL中格式化后的日期。接下來(lái),它檢測(cè)value是否像是一個(gè)具體時(shí)間。這是一個(gè)ActiveSupport中擴(kuò)展的方法,當(dāng)一個(gè)對(duì)象類(lèi)似Time類(lèi)型的實(shí)例時(shí),它會(huì)返回true。這讓它更容易表明各種對(duì)象已被假設(shè)為類(lèi)似Time的對(duì)象。(提示: 對(duì)acts_like?方法感興趣?請(qǐng)?jiān)诿钚兄袌?zhí)行qw activesupport,然后閱讀core_ext/object/acts_like.rb)
第二部分的條件檢查value是否有用于返回毫秒的usec方法。如果可以求得毫秒數(shù),那么它將通過(guò)sprintf方法被追加到result字符串的末尾。跟很多時(shí)間格式一樣,sprintf也有很多不同的方式用于格式化數(shù)字:

sprintf("%06d", 32) #=> "000032"sprintf("%6d", 32) #=> "  32"sprintf("%d",  32) #=> "32"sprintf("%.2f", 32) #=> "32.00"

最后,假如日期是一個(gè)負(fù)數(shù),PostgreSQLAdapter就會(huì)通過(guò)加上”BC”去重新格式化日期,這是PostgreSQL數(shù)據(jù)庫(kù)的實(shí)際要求:

SELECT '2000-01-20'::timestamp;-- 2000-01-20 00:00:00SELECT '2000-01-20 BC'::timestamp;-- 2000-01-20 00:00:00 BCSELECT '-2000-01-20'::timestamp;-- ERROR: time zone displacement out of range: "-2000-01-20"

這只是ActiveRecord適配多個(gè)API時(shí)的一個(gè)極小的方式,但它卻能幫助你免除由于不同數(shù)據(jù)庫(kù)的細(xì)節(jié)所帶來(lái)的差異和煩惱。
另一個(gè)體現(xiàn)SQL數(shù)據(jù)庫(kù)的不同點(diǎn)是數(shù)據(jù)庫(kù)表被創(chuàng)建的方式。MySQL以及PostgreSQL中對(duì)主鍵的處理各不相同:

# AbstractMysqlAdapterNATIVE_DATABASE_TYPES = { :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", #...}# PostgreSQLAdapterNATIVE_DATABASE_TYPES = { primary_key: "serial primary key", #...}

這兩種適配器都能夠明白ActiveRecord中的主鍵的表示方式,但是它們會(huì)在創(chuàng)建新表的時(shí)候?qū)⒋朔g為不同的SQL語(yǔ)句。當(dāng)你下次在編寫(xiě)一個(gè)migration或者執(zhí)行一個(gè)查詢(xún)的時(shí)候,思考一下ActiveRecord的適配器以及它們?yōu)槟阕龅乃形⑿〉氖虑椤?br />DateTime和Time
當(dāng)MultiJson以及ActiveRecord實(shí)現(xiàn)了傳統(tǒng)的適配器的時(shí)候,Ruby的靈活性使得另一種解決方案成為可能。DateTime以及Time都用于表示時(shí)間,但是它們?cè)趦?nèi)部的處理上是不同的。雖然有著這些細(xì)微的差異,但是它們所暴露出來(lái)的API卻是極其類(lèi)似的(提示:命令行中執(zhí)行qw activesupport查看此處相關(guān)代碼):

t = Time.nowt.day   #=> 19     (Day of month)t.wday  #=> 3     (Day of week)t.usec  #=> 371552   (Microseconds)t.to_i  #=> 1392871392 (Epoch secconds)d = DateTime.nowd.day   #=> 19     (Day of month)d.wday  #=> 3     (Day of week)d.usec  #=> NoMethodError: undefined method `usec'd.to_i  #=> NoMethodError: undefined method `to_i'

ActiveSupport通過(guò)添加缺失的方法來(lái)直接修改DateTime和Time,進(jìn)而抹平了兩者之間的差異。從實(shí)例上看,這里就有一個(gè)例子演示了ActiveSupport如何定義DateTime#to_i:

class DateTime def to_i  seconds_since_unix_epoch.to_i end def seconds_since_unix_epoch  (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight end def offset_in_seconds  (offset * 86400).to_i end def seconds_since_midnight  sec + (min * 60) + (hour * 3600) endend

每一個(gè)用于支持的方法,seconds_since_unix_epoch,offset_in_seconds,以及seconds_since_midnight都使用或者擴(kuò)展了DateTime中已經(jīng)存在的API去定義與Time中匹配的方法。
假如說(shuō)我們前面所看到的適配器是相對(duì)于被適配對(duì)象的外部適配器,那么我們現(xiàn)在所看到的這個(gè)就可以被稱(chēng)之為內(nèi)部適配器。與外部適配器不同的是,這種方法受限于已有的API,并且可能導(dǎo)致一些麻煩的矛盾問(wèn)題。舉例來(lái)說(shuō),DateTime和Time在一些特殊的場(chǎng)景下就有可能出現(xiàn)不一樣的行為:

datetime == time #=> truedatetime + 1   #=> 2014-02-26 07:32:39time + 1     #=> 2014-02-25 07:32:40

當(dāng)加上1的時(shí)候,DateTime加上了一天,而Time則是加上了一秒。當(dāng)你需要使用它們的時(shí)候,你要記住ActiveSupport基于這些不同,提供了諸如change和Duration等保證一致行為的方法或類(lèi)。
這是一個(gè)好的模式嗎?它理所當(dāng)然是方便的,但是如你剛才所見(jiàn),你仍舊需要注意其中的一些不同之處。
總結(jié)
設(shè)計(jì)模式不是只有Java才需要的。Rails通過(guò)使用設(shè)計(jì)模式以提供用于JSON解析以及數(shù)據(jù)庫(kù)維護(hù)的統(tǒng)一接口。由于Ruby的靈活性,類(lèi)似DateTime以及Time這樣的類(lèi)可以被直接地修改而提供相似的接口。Rails的源碼就是一個(gè)可以讓你挖掘真實(shí)世界中不同設(shè)計(jì)模式實(shí)例的天堂。
在這次的實(shí)踐中,我們同時(shí)也發(fā)掘了一些有趣的代碼:

  • hash[:foo] = hash.delete(:bar)是一個(gè)用于重命名哈希表中某一項(xiàng)的巧妙方法。
  • 調(diào)用::ClassName會(huì)調(diào)用頂層的類(lèi)。
  • ActiveSupport為T(mén)ime、Date以及其他的類(lèi)添加了一個(gè)可選的代表格式的參數(shù)format。
  • sprintf可以用于格式化數(shù)字。

想要探索更多的知識(shí)?回去看看MultiJson是如何處理以及解析格式的。仔細(xì)閱讀你在你的數(shù)據(jù)庫(kù)中所使用到的ActiveRecord的適配器的代碼。瀏覽ActiveSupport中用于xml適配器的XmlMini,它跟MultiJson中的JSON適配器是類(lèi)似的。在這些里面還會(huì)有很多可以學(xué)習(xí)的。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
欧美xxxxx性| 国产精品白浆流出视频| 国产丝袜精品丝袜| 国产在线观看18| 国产免费高清| 国产一区二区在线|播放| 国产一二在线观看| 在线播放av网站| 在线激情小视频| 丁香在线视频| 国产激情视频一区二区三区| 中文av字幕| 久久久久久久久亚洲精品| 国产欧美日韩第一页| 在线看a视频| 国产精选在线视频拍拍拍| 日本中文字幕在线播放| 国产午夜视频在线观看| 国产高清av| 久艹在线视频| 国产亚洲依依| 香蕉视频在线看| 99视频在线观看地址| 国产天堂资源| 国产在线视频福利| 亚洲久草视频| 国产黄视频在线观看| 免费a级毛片在线观看| 精品视频vs精品视频| 日本中文字幕在线播放| 欧美另类在线视频| 在线色视频网| 国产人成在线视频| 成在在线免费视频| 亚洲精品视频区| 精品国产福利一区二区在线| 中文字幕在线观看播放| 青青青国产视频| 亚洲视频网站在线| 尤物在线视频观看| 在线免费看黄网站| 在线观看视频污| 亚洲精品在线视频免费| 亚洲视频在线网| 久久五月精品| 天天操人人干| 国产精品臀控福利在线观看| 中文字幕在线免费视频| 国产一级影片| 国产youjizz在线| 国产www.大片在线| 伊人影院蕉久影院在线播放| 在线观看免费高清完整| 精品卡1卡2卡三卡免费网站| 国产一区二区三区福利| 国产情侣高潮对白| 99色在线观看| www免费在线观看视频| 日本福利在线观看| 狠狠操五月天| 国产精品爱久久久久久久小说 | 黄色一级视频网站| 五月综合激情在线| 2021av天天| 亚洲永久免费网站| 九九热视频在线| 最好看更新中文字幕| 天堂资源最新在线| av文字幕在线观看| 天天操夜夜操天天射| 亚洲国产成人综合| 国产无遮挡在线视频免费观看| 国产福利小视频在线观看| 亚洲欧美小说国产图片| 国产免费电影网站入口| 伊人影院在线播放| 国产精品视频一区二区久久| eeuss影院在线观看| 国产一卡2卡3卡四卡网站| 亚洲尤物在线视频| 国产一区二区三区四区尤物| 亚洲综合色视频在线观看| 国产乱精品一区二区三区| 怡红院av在线| 在线黄色国产电影| 国产高清免费av在线| 国产乱妇乱子| 黄色毛片在线| 福利在线国产| 九九精品九九| 欧美性猛交xxxx免费看蜜桃| 在线中文资源天堂| av黄色在线观看| 91极品在线| 2019中文字幕在线视频| 国产视频97| 最近久乱中文字幕| 国产一级性片| 国产羞羞视频在线观看| 国产麻豆视频免费观看| 男女羞羞视频在线观看| 日本在线天堂| 本道综合精品| 成av人免费青青久| 国产女人在线观看| 中文字幕av中文字幕| 国产亚洲精品拍拍拍拍拍| 国产污污在线观看| 国产盗摄一区二区| 精品精品导航| 欧美性猛交p30| 九色在线网站| 国产免费自拍视频| 国产午夜视频在线观看| 夜夜爽夜夜操| 7777在线| 69日小视频在线观看| 国产高清av| 午夜性爽视频男人的天堂| 日本调教视频在线观看| 国产专区在线| 国产精品剧情一区二区三区 | 欧美日韩久久中文字幕| a视频在线观看免费| 男女午夜视频在线观看| 99热在线免费播放| 精品成人免费自拍视频| 女同一区二区免费aⅴ| 午夜伦全在线观看| 在线看黄色av| 国产精品久久久久永久免费看| 国产情侣高潮对白| 日本精品一区二区三区在线播放| 久久一本精品| 精品欧美日韩一区二区| 久久精品国产亚洲a∨麻豆| 国产人成在线视频| 夜夜操天天干| 国产三级视频在线看| h视频在线网站| 国产福利一区二区在线精品| 超碰国产在线观看| 亚洲欧美中文字幕在线观看| 国产伦精品一区二区三区高清版禁| 国产福利微拍精品一区二区| 欧美日韩一区二区三区在线播放 | 91xxx在线观看| 天天草天天干| 在线观看免费高清完整| 国产免费一级片| 天天艹天天操| 在线天堂av| av福利在线| 国产二区三区四区| 国产精品久久久精品a级小说| 免费国产视频| 不卡av免费观看| 在线观看中文字幕的网站| 国产日韩欧美一区二区三区视频| 国产69久久| 久久国产热视频| 六月天色婷婷| 久草在线视频网| 狠狠狠综合7777久夜色撩人| www在线免费观看视频| 小说区乱图片区| 四虎影视成人永久免费观看视频| 国产二级片在线| 中文字幕av免费| 亚洲成人国产综合| 亚洲精品影院在线| 欧洲亚洲精品视频| 国产麻豆免费| 国产精品777一区二区| 2021av天天| 久色视频在线观看| 最近免费中文字幕大全免费第三页 | 九九热在线视频| 国产在线观看色| 国产精品毛片一区二区三区四区| 国产精品免费视频一区一| 国产精品爱久久久久久久小说| √天堂资源中文www| 日日夜夜中文字幕| 天堂在线视频| 国产精品久久久高清免费| 中文字幕av高清| 久热av在线| 96久久久久久| av中文字幕在线看| 国产一区久久精品| 国产95在线|亚洲| 另类专区欧美| 2021av在线| 狠狠综合久久久综合| 精品99又大又爽又硬少妇毛片 | 免费高清视频日韩| 国产欧美日韩专区| 久久亚洲国产成人亚| 精品176二区|