婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Ruby設計模式編程之適配器模式實戰(zhàn)攻略

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

熱門標簽:湖州u友防封電銷卡 白銀外呼paas系統(tǒng) 高德地圖標注客服 滴滴外呼系統(tǒng) 徐州網(wǎng)絡外呼系統(tǒng)哪個好 常德電銷平臺外呼系統(tǒng)軟件價格 電銷機器人廠商代理 百度地圖標注自定義圖片 地圖標注賺錢項目注冊

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

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

我們假設有一個針對locator的接口,但是如果我們想要find_nearest_restaurant能夠支持另一個庫呢?這個時候我們可能就會去嘗試添加新的特殊的場景的處理:

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."
 end
end

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

def find_nearest_hospital(locator)
 locator.find :type => :hospital,
        :lat => self.lat,
        :lon => self.lon
end

locator = GeoFishAdapter.new(geo_fish_locator)
find_nearest_hospital(locator)

特意假設的例子就到此為止,接下來讓我們看看真實的代碼。

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

接著定義三個統(tǒng)計類繼承PlayerCount,分別對應了三個不同的服,如下所示:

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 

然后定義一個XMLBuilder類,用于將各服的數(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 

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

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

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

MultiJSON
ActiveSupport在做JSON格式的解碼時,用到的是MultiJSON,這是一個針對JSON庫的適配器。每一個庫都能夠解析JSON,但是做法卻不盡相同。讓我們分別看看針對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項轉(zhuǎn)換為Oj的:symbol_keys項:

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

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

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

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

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

Rails中的ActiveSupport擴展了Time#to_s,使其能夠接收一個代表格式名的符號類型參數(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的適配器都沒有重寫quoted_date方法,它們自然會繼承這種行為。另一邊,PostgreSQLAdapter則對日期的處理做了兩個修改:

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
 result
end

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

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

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

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

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

# AbstractMysqlAdapter
NATIVE_DATABASE_TYPES = {
 :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
 #...
}

# PostgreSQLAdapter
NATIVE_DATABASE_TYPES = {
 primary_key: "serial primary key",
 #...
}

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

t = Time.now
t.day   #=> 19     (Day of month)
t.wday  #=> 3     (Day of week)
t.usec  #=> 371552   (Microseconds)
t.to_i  #=> 1392871392 (Epoch secconds)

d = DateTime.now
d.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通過添加缺失的方法來直接修改DateTime和Time,進而抹平了兩者之間的差異。從實例上看,這里就有一個例子演示了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)
 end
end

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

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

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

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

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

您可能感興趣的文章:
  • 設計模式中的觀察者模式在Ruby編程中的運用實例解析
  • 實例解析Ruby設計模式開發(fā)中對觀察者模式的實現(xiàn)
  • 深入剖析Ruby設計模式編程中對命令模式的相關(guān)使用
  • Ruby設計模式編程中對外觀模式的應用實例分析
  • 詳解組合模式的結(jié)構(gòu)及其在Ruby設計模式編程中的運用
  • 設計模式中的模板方法模式在Ruby中的應用實例兩則
  • 實例解析Ruby設計模式編程中Strategy策略模式的使用
  • 實例講解Ruby使用設計模式中的裝飾器模式的方法
  • Ruby設計模式編程中使用Builder建造者模式的實例
  • 詳解Ruby設計模式編程中對單例模式的運用
  • Ruby使用設計模式中的代理模式與裝飾模式的代碼實例
  • Ruby中使用設計模式中的簡單工廠模式和工廠方法模式
  • 解析proxy代理模式在Ruby設計模式開發(fā)中的運用

標簽:張家界 梧州 三沙 永州 普洱 遼寧 公主嶺 荊門

巨人網(wǎng)絡通訊聲明:本文標題《Ruby設計模式編程之適配器模式實戰(zhàn)攻略》,本文關(guān)鍵詞  Ruby,設計模式,編程,之,適配器,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡,涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Ruby設計模式編程之適配器模式實戰(zhàn)攻略》相關(guān)的同類信息!
  • 本頁收集關(guān)于Ruby設計模式編程之適配器模式實戰(zhàn)攻略的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    亚洲三级小视频| 亚洲免费av高清| 天天综合网天天综合色| 日韩av一区二区三区| 日韩激情视频在线观看| 亚洲18色成人| 天天综合网天天综合色| 亚洲精品精品亚洲| 亚洲乱码国产乱码精品精小说| 久久久99精品免费观看不卡| 欧美大肚乱孕交hd孕妇| 国产欧美日韩在线看| 国产午夜亚洲精品午夜鲁丝片| 国产日韩欧美激情| 国产精品国产三级国产aⅴ原创| 国产精品看片你懂得| 亚洲国产日韩av| 午夜成人免费电影| 狠狠色丁香久久婷婷综合_中| 国产成人综合自拍| 欧美性感一类影片在线播放| 亚洲精品一区二区三区蜜桃下载| 国产视频亚洲色图| 日本成人在线不卡视频| 粉嫩欧美一区二区三区高清影视| 成人免费观看av| 欧美一区二区网站| 久久综合久久99| 欧美视频一区二区三区四区 | 91玉足脚交白嫩脚丫在线播放| 亚洲动漫第一页| 亚洲欧美日韩国产一区二区三区| 日韩免费电影一区| 日韩一级大片在线观看| 玉足女爽爽91| 色www精品视频在线观看| 久久久蜜臀国产一区二区| 蜜桃一区二区三区在线| 欧洲生活片亚洲生活在线观看| 国产欧美一区二区精品秋霞影院 | 国产精品无遮挡| 国内久久精品视频| 欧美mv和日韩mv的网站| 老司机午夜精品| 欧美不卡激情三级在线观看| 日韩国产一区二| 日韩美一区二区三区| 老司机午夜精品99久久| 久久亚洲一级片| 成人性视频免费网站| 一区二区三区精品视频在线| 欧美日韩国产一级二级| 国内精品伊人久久久久影院对白| 国产精品久久久久久亚洲毛片| 成人午夜私人影院| 欧美天堂一区二区三区| 久久伊人蜜桃av一区二区| 久久在线观看免费| 亚洲综合视频网| 色综合久久天天| 欧美日韩国产首页| 国产欧美日韩激情| 日韩高清不卡一区| 色婷婷久久综合| 一本色道久久加勒比精品| 精品综合久久久久久8888| 亚洲主播在线播放| 中文字幕一区二区三区精华液| 欧美日韩免费视频| 欧美亚洲高清一区| 成人自拍视频在线观看| 国产成人无遮挡在线视频| 美女视频第一区二区三区免费观看网站| 亚洲视频免费看| 国产精品污污网站在线观看| 国产欧美在线观看一区| 久久免费看少妇高潮| 久久亚洲综合色| 国产日韩视频一区二区三区| 日韩西西人体444www| 精品久久久久久久久久久久久久久| 欧美主播一区二区三区| 91福利国产精品| 91精品国产品国语在线不卡| 欧美一级日韩不卡播放免费| 欧美精品一区二区三区蜜桃| 欧美白人最猛性xxxxx69交| 精品奇米国产一区二区三区| 日韩女优制服丝袜电影| 粉嫩一区二区三区在线看| 国产精品毛片久久久久久| 96av麻豆蜜桃一区二区| 亚洲国产一区二区三区| 777色狠狠一区二区三区| 国产一区二区三区| 国产精品久久久久久亚洲毛片| 91在线视频官网| 香蕉久久夜色精品国产使用方法 | 成人性生交大片免费看中文网站| 99re免费视频精品全部| 欧美一区二区视频在线观看2020 | 91麻豆精品视频| 国产日韩精品一区二区三区| 亚洲国产成人va在线观看天堂| 精品一区二区在线免费观看| 91亚洲大成网污www| 精品国产成人在线影院| 日欧美一区二区| 99精品视频在线播放观看| 欧美精品一区二区三区蜜桃| 日本欧美大码aⅴ在线播放| 色哟哟精品一区| 亚洲色图制服丝袜| 国产乱码精品一区二区三区忘忧草| 欧美天堂亚洲电影院在线播放| 日本一区二区高清| 99国产麻豆精品| 亚洲男帅同性gay1069| 99精品视频在线观看| 国产精品萝li| 欧美日韩一区视频| 欧美午夜电影在线播放| 在线免费视频一区二区| 一本大道久久a久久精二百| 国产成人精品免费在线| 成人蜜臀av电影| 97久久人人超碰| 欧美系列日韩一区| 欧美一级淫片007| 国产亚洲精品7777| 国产精品久久久久9999吃药| 激情av综合网| 亚洲成人精品一区| 中文字幕av一区二区三区高 | 99精品热视频| 日韩av网站在线观看| 国产精品久久久久婷婷| 欧美一区二区三区在线视频| 成人综合婷婷国产精品久久蜜臀| 亚洲一区二区三区小说| 国产婷婷色一区二区三区四区 | 精品美女一区二区| 欧美精品黑人性xxxx| 91香蕉国产在线观看软件| 麻豆国产精品视频| 视频在线观看一区| 一区二区日韩电影| 亚洲人成网站精品片在线观看| 日韩精品一区二区三区老鸭窝| 成人免费黄色大片| 成人精品视频一区二区三区| 日本欧美一区二区三区| 日本伊人精品一区二区三区观看方式| 欧美性受极品xxxx喷水| 国产精品白丝在线| 成人18精品视频| 国产日韩一级二级三级| 国产一区免费电影| 日韩欧美不卡一区| 美女www一区二区| 欧美成人国产一区二区| 日本欧美一区二区在线观看| 日本韩国精品一区二区在线观看| 欧美高清在线精品一区| 精品一区二区三区在线观看国产 | 香蕉久久一区二区不卡无毒影院 | 欧美手机在线视频| 欧美乱妇20p| 精品国产亚洲在线| 亚洲日本va午夜在线影院| 一区二区三区在线免费观看| 日本在线播放一区二区三区| 国产精品综合一区二区三区| 成人性生交大片免费| 欧美精品精品一区| 久久久精品一品道一区| 亚洲最新视频在线观看| 麻豆成人久久精品二区三区小说| 成人黄色软件下载| 日韩欧美在线影院| 亚洲一区二区中文在线| 国产精品一线二线三线精华| 91碰在线视频| 中文字幕乱码日本亚洲一区二区| 亚洲第一主播视频| 国产在线视频不卡二| 欧美一区二区网站| 一区二区三区在线免费视频| 国产精品一区二区x88av| 欧美日韩激情在线| 亚洲国产一二三| 欧美三级日本三级少妇99| 亚洲精选在线视频| 欧美视频中文字幕| 婷婷成人综合网| 欧美一区二区二区| 奇米在线7777在线精品| 69久久夜色精品国产69蝌蚪网| 国产精品国产三级国产普通话99 | 成人福利视频在线看|