3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

代码原则

發布時間:2025/3/21 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 代码原则 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、優化代碼的第一步——單一職責原則

單一職責原則的英文名稱是Single Responsibility Principle,簡稱SRP。它的定義是:就一個類而言,應該僅有一個引起它變化的原因。簡單來說,一個類中應該是一組相關性很高的函數、數據的封裝。就像秦小波老師在《設計模式之禪》中說的:“這是一個備受爭議卻又及其重要的原則。只要你想和別人爭執、慪氣或者是吵架,這個原則是屢試不爽的”。因為單一職責的劃分界限并不是總是那么清晰,很多時候都是需要靠個人經驗來界定。當然,最大的問題就是對職責的定義,什么是類的職責,以及怎么劃分類的職責。
對于計算機技術,通常只單純地學習理論知識并不能很好地領會其深意,只有自己動手實踐,并在實際運用中發現問題、解決問題、思考問題,才能夠將知識吸收到自己的腦海中。下面以我的朋友小民的事跡說起。

自從Android系統發布以來,小民就是Android的鐵桿粉絲,于是在大學期間一直保持著對Android的關注,并且利用課余時間做些小項目,鍛煉自己的實戰能力。畢業后,小民如愿地加入了心儀的公司,并且投入到了他熱愛的Android應用開發行業中。將愛好、生活、事業融為一體,小民的第一份工作也算是順風順水,一切盡在掌握中。
在經歷過一周的適應期以及熟悉公司的產品、開發規范之后,小民的開發工作就正式開始了。小民的主管是個工作經驗豐富的技術專家,對于小民的工作并不是很滿意,尤其小民最薄弱的面向對象設計,而Android開發又是使用Java語言,什么抽象、接口、六大原則、23種設計模式等名詞把小民弄得暈頭轉向。小民自己也察覺到了自己的問題所在,于是,小民的主管決定先讓小民做一個小項目來鍛煉鍛煉這方面的能力。正所謂養兵千日用兵一時,磨刀不誤砍柴工,小民的開發之路才剛剛開始。

在經過一番思考之后,主管挑選了使用范圍廣、難度也適中的ImageLoader(圖片加載)作為小民的訓練項目。既然要訓練小民的面向對象設計,那么就必須考慮到可擴展性、靈活性,而檢測這一切是否符合需求的最好途徑就是開源。用戶不斷地提出需求、反饋問題,小民的項目需要不斷升級以滿足用戶需求,并且要保證系統的穩定性、靈活性。在主管跟小民說了這一特殊任務之后,小民第一次感到了壓力,“生活不容易吶!”年僅22歲至今未婚的小民發出了如此深刻的感嘆!

挑戰總是要面對的,何況是從來不服輸的小民。主管的要求很簡單,要小民實現圖片加載,并且要將圖片緩存起來。在分析了需求之后,小民一下就放心下來了,“這么簡單,原來我還以為很難呢……”小民胸有成足的喃喃自語。在經歷了十分鐘的編碼之后,小民寫下了如下代碼:

<code class="language-java hljs has-numbering"><span class="hljs-javadoc">/*** 圖片加載類*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 圖片緩存</span>LruCache<String, Bitmap> mImageCache;<span class="hljs-comment">// 線程池,線程數量為CPU的數量</span>ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());<span class="hljs-keyword">public</span> <span class="hljs-title">ImageLoader</span>() {initImageCache();}<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initImageCache</span>() {<span class="hljs-comment">// 計算可使用的最大內存</span><span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> maxMemory = (<span class="hljs-keyword">int</span>) (Runtime.getRuntime().maxMemory() / <span class="hljs-number">1024</span>);<span class="hljs-comment">// 取四分之一的可用內存作為緩存</span><span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> cacheSize = maxMemory / <span class="hljs-number">4</span>;mImageCache = <span class="hljs-keyword">new</span> LruCache<String, Bitmap>(cacheSize) {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">int</span> <span class="hljs-title">sizeOf</span>(String key, Bitmap bitmap) {<span class="hljs-keyword">return</span> bitmap.getRowBytes() * bitmap.getHeight() / <span class="hljs-number">1024</span>;}};} <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(<span class="hljs-keyword">final</span> String url, <span class="hljs-keyword">final</span> ImageView imageView) {imageView.setTag(url);mExecutorService.submit(<span class="hljs-keyword">new</span> Runnable() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {Bitmap bitmap = downloadImage(url);<span class="hljs-keyword">if</span> (bitmap == <span class="hljs-keyword">null</span>) {<span class="hljs-keyword">return</span>;}<span class="hljs-keyword">if</span> (imageView.getTag().equals(url)) {imageView.setImageBitmap(bitmap);}mImageCache.put(url, bitmap);}});}<span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">downloadImage</span>(String imageUrl) {Bitmap bitmap = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {URL url = newURL(imageUrl);<span class="hljs-keyword">final</span> HttpURLConnection conn = (HttpURLConnection)url.openConnection();bitmap = BitmapFactory.decodeStream(conn.getInputStream());conn.disconnect();} <span class="hljs-keyword">catch</span> (Exception e) {e.printStackTrace();}<span class="hljs-keyword">return</span> bitmap;} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li></ul>

并且使用git軟件進行版本控制,將工程托管到github上,伴隨著git push命令的完成,小民的ImageLoader 0.1版本就正式發布了!如此短的時間內就完成了這個任務,而且還是一個開源項目,小民暗暗自喜,幻想著待會兒主管的稱贊。

在小民給主管報告了ImageLoader的發布消息的幾分鐘之后,主管就把小民叫到了會議室。這下小民納悶了,怎么夸人還需要到會議室。“小民,你的ImageLoader耦合太嚴重啦!簡直就沒有設計可言,更不要說擴展性、靈活性了。所有的功能都寫在一個類里怎么行呢,這樣隨著功能的增多,ImageLoader類會越來越大,代碼也越來越復雜,圖片加載系統就越來越脆弱……”Duang,這簡直就是當頭棒喝,小民的腦海里已經聽不清主管下面說的內容了,只是覺得自己之前沒有考慮清楚就匆匆忙忙完成任務,而且把任務想得太簡單了。

“你還是把ImageLoader拆分一下,把各個功能獨立出來,讓它們滿足單一職責原則。”主管最后說道。小民是個聰明人,敏銳地捕捉到了單一職責原則這個關鍵詞。用Google搜索了一些優秀資料之后總算是對單一職責原則有了一些認識。于是打算對ImageLoader進行一次重構。這次小民不敢過于草率,也是先畫了一幅UML圖,如圖1-1所示。

圖1-1

ImageLoader代碼修改如下所示:

<code class="language-java hljs has-numbering"><span class="hljs-javadoc">/*** 圖片加載類*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 圖片緩存</span>ImageCache mImageCache = <span class="hljs-keyword">new</span> ImageCache() ;<span class="hljs-comment">// 線程池,線程數量為CPU的數量</span>ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());<span class="hljs-comment">// 加載圖片</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(<span class="hljs-keyword">final</span> String url, <span class="hljs-keyword">final</span> ImageView imageView) {Bitmap bitmap = mImageCache.get(url);<span class="hljs-keyword">if</span> (bitmap != <span class="hljs-keyword">null</span>) {imageView.setImageBitmap(bitmap);<span class="hljs-keyword">return</span>;}imageView.setTag(url);mExecutorService.submit(<span class="hljs-keyword">new</span> Runnable() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {Bitmap bitmap = downloadImage(url);<span class="hljs-keyword">if</span> (bitmap == <span class="hljs-keyword">null</span>) {<span class="hljs-keyword">return</span>;}<span class="hljs-keyword">if</span> (imageView.getTag().equals(url)) {imageView.setImageBitmap(bitmap);}mImageCache.put(url, bitmap);}});}<span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">downloadImage</span>(String imageUrl) {Bitmap bitmap = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {URL url = <span class="hljs-keyword">new</span> URL(imageUrl);<span class="hljs-keyword">final</span> HttpURLConnection conn = (HttpURLConnection) url.openConnection();bitmap = BitmapFactory.decodeStream(conn.getInputStream());conn.disconnect();} <span class="hljs-keyword">catch</span> (Exception e) {e.printStackTrace();}<span class="hljs-keyword">return</span> bitmap;} } </code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li></ul>

并且添加了一個ImageCache類用于處理圖片緩存,具體代碼如下:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageCache</span> {</span><span class="hljs-comment">// 圖片LRU緩存</span>LruCache<String, Bitmap> mImageCache;<span class="hljs-keyword">public</span> <span class="hljs-title">ImageCache</span>() {initImageCache();}<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initImageCache</span>() {<span class="hljs-comment">// 計算可使用的最大內存</span><span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> maxMemory = (<span class="hljs-keyword">int</span>) (Runtime.getRuntime().maxMemory() / <span class="hljs-number">1024</span>);<span class="hljs-comment">// 取四分之一的可用內存作為緩存</span><span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> cacheSize = maxMemory / <span class="hljs-number">4</span>;mImageCache = <span class="hljs-keyword">new</span> LruCache<String, Bitmap>(cacheSize) {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">int</span> <span class="hljs-title">sizeOf</span>(String key, Bitmap bitmap) {<span class="hljs-keyword">return</span> bitmap.getRowBytes() * bitmap.getHeight() / <span class="hljs-number">1024</span>;}};}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bitmap) {mImageCache.put(url, bitmap) ;}<span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {<span class="hljs-keyword">return</span> mImageCache.get(url) ;} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>

如圖1-1和上述代碼所示,小民將ImageLoader一拆為二,ImageLoader只負責圖片加載的邏輯,而ImageCache只負責處理圖片緩存的邏輯,這樣ImageLoader的代碼量變少了,職責也清晰了,當與緩存相關的邏輯需要改變時,不需要修改ImageLoader類,而圖片加載的邏輯需要修改時也不會影響到緩存處理邏輯。主管在審核了小民的第一次重構之后,對小民的工作給予了表揚,大致意思是結構變得清晰了許多,但是可擴展性還是比較欠缺,雖然沒有得到主管的完全肯定,但也是頗有進步,再考慮到自己確實有所收獲,小民原本沮喪的心里也略微地好轉起來。

從上述的例子中我們能夠體會到,單一職責所表達出的用意就是“單一”二字。正如上文所說,如何劃分一個類、一個函數的職責,每個人都有自己的看法,這需要根據個人經驗、具體的業務邏輯而定。但是,它也有一些基本的指導原則,例如,兩個完全不一樣的功能就不應該放在一個類中。一個類中應該是一組相關性很高的函數、數據的封裝。工程師可以不斷地審視自己的代碼,根據具體的業務、功能對類進行相應的拆分,我想這會是你優化代碼邁出的第一步。

2、讓程序更穩定、更靈活——開閉原則

開閉原則的英文全稱是Open Close Principle,簡稱OCP,它是Java世界里最基礎的設計原則,它指導我們如何建立一個穩定的、靈活的系統。開閉原則的定義是:軟件中的對象(類、模塊、函數等)應該對于擴展是開放的,但是,對于修改是封閉的。在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會將錯誤引入原本已經經過測試的舊代碼中,破壞原有系統。因此,當軟件需要變化時,我們應該盡量通過擴展的方式來實現變化,而不是通過修改已有的代碼來實現。當然,在現實開發中,只通過繼承的方式來升級、維護原有系統只是一個理想化的愿景,因此,在實際的開發過程中,修改原有代碼、擴展代碼往往是同時存在的。

軟件開發過程中,最不會變化的就是變化本身。產品需要不斷地升級、維護,沒有一個產品從第一版本開發完就再沒有變化了,除非在下個版本誕生之前它已經被終止。而產品需要升級,修改原來的代碼就可能會引發其他的問題。那么如何確保原有軟件模塊的正確性,以及盡量少地影響原有模塊,答案就是盡量遵守本章要講述的開閉原則。

勃蘭特·梅耶在1988年出版的《面向對象軟件構造》一書中提出這一原則。這一想法認為,一旦完成,一個類的實現只應該因錯誤而被修改,新的或者改變的特性應該通過新建不同的類實現。新建的類可以通過繼承的方式來重用原類的代碼。顯然,梅耶的定義提倡實現繼承,已存在的實現對于修改是封閉的,但是新的實現類可以通過覆寫父類的接口應對變化。
說了這么多,想必大家還是半懂不懂,還是讓我們以一個簡單示例說明一下吧。

在對ImageLoader進行了一次重構之后,小民的這個開源庫獲得了一些用戶。小民第一次感受到自己發明“輪子”的快感,對開源的熱情也越發高漲起來!通過動手實現一些開源庫來深入學習相關技術,不僅能夠提升自我,也能更好地將這些技術運用到工作中,從而開發出更穩定、優秀的應用,這就是小民的真實想法。

小民第一輪重構之后的ImageLoader職責單一、結構清晰,不僅獲得了主管的一點肯定,還得到了用戶的夸獎,算是個不錯的開始。隨著用戶的增多,有些問題也暴露出來了,小民的緩存系統就是大家“吐槽”最多的地方。通過內存緩存解決了每次從網絡加載圖片的問題,但是,Android應用的內存很有限,且具有易失性,即當應用重新啟動之后,原來已經加載過的圖片將會丟失,這樣重啟之后就需要重新下載!這又會導致加載緩慢、耗費用戶流量的問題。小民考慮引入SD卡緩存,這樣下載過的圖片就會緩存到本地,即使重啟應用也不需要重新下載了!小民在和主管討論了該問題之后就投入了編程中,下面就是小民的代碼。
DiskCache.java類,將圖片緩存到SD卡中:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DiskCache</span> {</span><span class="hljs-comment">// 為了簡單起見臨時寫個路徑,在開發中請避免這種寫法 !</span><span class="hljs-keyword">static</span> String cacheDir = <span class="hljs-string">"sdcard/cache/"</span>;<span class="hljs-comment">// 從緩存中獲取圖片</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {<span class="hljs-keyword">return</span> BitmapFactory.decodeFile(cacheDir + url);}<span class="hljs-comment">// 將圖片緩存到內存中</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {FileOutputStream fileOutputStream = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {fileOutputStream = <span class="hljs-keyword">new</span> FileOutputStream(cacheDir + url);bmp.compress(CompressFormat.PNG, <span class="hljs-number">100</span>, fileOutputStream);} <span class="hljs-keyword">catch</span> (FileNotFoundException e) {e.printStackTrace();} <span class="hljs-keyword">final</span> ly {<span class="hljs-keyword">if</span> (fileOutputStream != <span class="hljs-keyword">null</span>) {<span class="hljs-keyword">try</span> {fileOutputStream.close();} <span class="hljs-keyword">catch</span> (IOException e) {e.printStackTrace();}}}} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li></ul>

因為需要將圖片緩存到SD卡中,所以,ImageLoader代碼有所更新,具體代碼如下:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 內存緩存</span>ImageCache mImageCache = <span class="hljs-keyword">new</span> ImageCache();<span class="hljs-comment">// SD卡緩存</span>DiskCache mDiskCache = <span class="hljs-keyword">new</span> DiskCache();<span class="hljs-comment">// 是否使用SD卡緩存</span><span class="hljs-keyword">boolean</span> isUseDiskCache = <span class="hljs-keyword">false</span>;<span class="hljs-comment">// 線程池,線程數量為CPU的數量</span>ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(<span class="hljs-keyword">final</span> String url, <span class="hljs-keyword">final</span> ImageView imageView) {<span class="hljs-comment">// 判斷使用哪種緩存</span>Bitmap bitmap = isUseDiskCache ? mDiskCache.get(url) : mImageCache.get (url);<span class="hljs-keyword">if</span> (bitmap != <span class="hljs-keyword">null</span>) {imageView.setImageBitmap(bitmap);<span class="hljs-keyword">return</span>;}<span class="hljs-comment">// 沒有緩存,則提交給線程池進行下載</span>}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">useDiskCache</span>(<span class="hljs-keyword">boolean</span> useDiskCache) {isUseDiskCache = useDiskCache ;} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li></ul>

從上述的代碼中可以看到,僅僅新增了一個DiskCache類和往ImageLoader類中加入了少量代碼就添加了SD卡緩存的功能,用戶可以通過useDiskCache方法來對使用哪種緩存進行設置,例如:

<code class="language-java hljs has-numbering">ImageLoader imageLoader = <span class="hljs-keyword">new</span> ImageLoader() ;<span class="hljs-comment">// 使用SD卡緩存</span> imageLoader.useDiskCache(<span class="hljs-keyword">true</span>); <span class="hljs-comment">// 使用內存緩存</span> imageLoader.useDiskCache(<span class="hljs-keyword">false</span>);</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

通過useDiskCache方法可以讓用戶設置不同的緩存,非常方便啊!小民對此很滿意,于是提交給主管做代碼審核。“小民,你思路是對的,但是有些明顯的問題,就是使用內存緩存時用戶就不能使用SD卡緩存,類似的,使用SD卡緩存時用戶就不能使用內存緩存。用戶需要這兩種策略的綜合,首先緩存優先使用內存緩存,如果內存緩存沒有圖片再使用SD卡緩存,如果SD卡中也沒有圖片最后才從網絡上獲取,這才是最好的緩存策略。”主管真是一針見血,小民這時才如夢初醒,剛才還得意洋洋的臉上突然有些泛紅……
于是小民按照主管的指點新建了一個雙緩存類DoudleCache,具體代碼如下:

<code class="language-java hljs has-numbering"><span class="hljs-javadoc">/*** 雙緩存。獲取圖片時先從內存緩存中獲取,如果內存中沒有緩存該圖片,再從SD卡中獲取。* 緩存圖片也是在內存和SD卡中都緩存一份*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DoubleCache</span> {</span>ImageCache mMemoryCache = <span class="hljs-keyword">new</span> ImageCache();DiskCache mDiskCache = <span class="hljs-keyword">new</span> DiskCache();<span class="hljs-comment">// 先從內存緩存中獲取圖片,如果沒有,再從SD卡中獲取</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {Bitmap bitmap = mMemoryCache.get(url);<span class="hljs-keyword">if</span> (bitmap == <span class="hljs-keyword">null</span>) {bitmap = mDiskCache.get(url);}<span class="hljs-keyword">return</span> bitmap;}<span class="hljs-comment">// 將圖片緩存到內存和SD卡中</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {mMemoryCache.put(url, bmp);mDiskCache.put(url, bmp);} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul>

我們再看看最新的ImageLoader類吧,代碼更新也不多:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 內存緩存</span>ImageCache mImageCache = <span class="hljs-keyword">new</span> ImageCache();<span class="hljs-comment">// SD卡緩存</span>DiskCache mDiskCache = <span class="hljs-keyword">new</span> DiskCache();<span class="hljs-comment">// 雙緩存</span>DoubleCache mDoubleCache = <span class="hljs-keyword">new</span> DoubleCache() ;<span class="hljs-comment">// 使用SD卡緩存</span><span class="hljs-keyword">boolean</span> isUseDiskCache = <span class="hljs-keyword">false</span>;<span class="hljs-comment">// 使用雙緩存</span><span class="hljs-keyword">boolean</span> isUseDoubleCache = <span class="hljs-keyword">false</span>;<span class="hljs-comment">// 線程池,線程數量為CPU的數量</span>ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(<span class="hljs-keyword">final</span> String url, <span class="hljs-keyword">final</span> ImageView imageView) {Bitmap bmp = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">if</span> (isUseDoubleCache) {bmp = mDoubleCache.get(url);} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (isUseDiskCache) {bmp = mDiskCache.get(url);} <span class="hljs-keyword">else</span> {bmp = mImageCache.get(url);}<span class="hljs-keyword">if</span> ( bmp != <span class="hljs-keyword">null</span> ) {imageView.setImageBitmap(bmp);}<span class="hljs-comment">// 沒有緩存,則提交給線程池進行異步下載圖片</span>}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">useDiskCache</span>(<span class="hljs-keyword">boolean</span> useDiskCache) {isUseDiskCache = useDiskCache ;}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">useDoubleCache</span>(<span class="hljs-keyword">boolean</span> useDoubleCache) {isUseDoubleCache = useDoubleCache ;} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li></ul>

通過增加短短幾句代碼和幾處修改就完成了如此重要的功能。小民已越發覺得自己Android開發已經到了的得心應手的境地,不僅感覺一陣春風襲來,他那飄逸的頭發一下從他的眼前拂過,小民感覺今天天空比往常敞亮許多。

“小民,你每次加新的緩存方法時都要修改原來的代碼,這樣很可能會引入Bug,而且會使原來的代碼邏輯變得越來越復雜,按照你這樣的方法實現,用戶也不能自定義緩存實現呀!”到底是主管水平高,一語道出了小民這緩存設計上的問題。

我們還是來分析一下小民的程序,小民每次在程序中加入新的緩存實現時都需要修改ImageLoader類,然后通過一個布爾變量來讓用戶使用哪種緩存,因此,就使得在ImageLoader中存在各種if-else判斷,通過這些判斷來確定使用哪種緩存。隨著這些邏輯的引入,代碼變得越來越復雜、脆弱,如果小民一不小心寫錯了某個if條件(條件太多,這是很容易出現的),那就需要更多的時間來排除。整個ImageLoader類也會變得越來越臃腫。最重要的是用戶不能自己實現緩存注入到ImageLoader中,可擴展性可是框架的最重要特性之一。

“軟件中的對象(類、模塊、函數等)應該對于擴展是開放的,但是對于修改是封閉的,這就是開放-關閉原則。也就是說,當軟件需要變化時,我們應該盡量通過擴展的方式來實現變化,而不是通過修改已有的代碼來實現。”小民的主管補充到,小民聽得云里霧里的。主管看小民這等反應,于是親自“操刀”,為他畫下了如圖1-2的UML圖。


圖1-2

小民看到圖1-2似乎明白些什么,但是又不是太明確如何修改程序。主管看到小民這般模樣只好親自上陣,帶著小民把ImageLoader程序按照圖1-2進行了一次重構。具體代碼如下:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 圖片緩存</span>ImageCache mImageCache = <span class="hljs-keyword">new</span> MemoryCache();<span class="hljs-comment">// 線程池,線程數量為CPU的數量</span>ExecutorService mExecutorService = Executors.newFixedThreadPool (Runtime.getRuntime().availableProcessors());<span class="hljs-comment">// 注入緩存實現</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setImageCache</span>(ImageCache cache) {mImageCache = cache;}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(String imageUrl, ImageView imageView) {Bitmap bitmap = mImageCache.get(imageUrl);<span class="hljs-keyword">if</span> (bitmap != <span class="hljs-keyword">null</span>) {imageView.setImageBitmap(bitmap);<span class="hljs-keyword">return</span>;}<span class="hljs-comment">// 圖片沒緩存,提交到線程池中下載圖片</span>submitLoadRequest(imageUrl, imageView);}<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">submitLoadRequest</span>(<span class="hljs-keyword">final</span> String imageUrl,<span class="hljs-keyword">final</span> ImageView imageView) {imageView.setTag(imageUrl);mExecutorService.submit(<span class="hljs-keyword">new</span> Runnable() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() {Bitmap bitmap = downloadImage(imageUrl);<span class="hljs-keyword">if</span> (bitmap == <span class="hljs-keyword">null</span>) {<span class="hljs-keyword">return</span>;}<span class="hljs-keyword">if</span> (imageView.getTag().equals(imageUrl)) {imageView.setImageBitmap(bitmap);}mImageCache.put(imageUrl, bitmap);}});}<span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">downloadImage</span>(String imageUrl) {Bitmap bitmap = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {URL url = <span class="hljs-keyword">new</span> URL(imageUrl);<span class="hljs-keyword">final</span> HttpURLConnection conn = (HttpURLConnection) url.openConnection();bitmap = BitmapFactory.decodeStream(conn.getInputStream());conn.disconnect();} <span class="hljs-keyword">catch</span> (Exception e) {e.printStackTrace();}<span class="hljs-keyword">return</span> bitmap;} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li></ul>

經過這次重構,沒有了那么多的if-else語句,沒有了各種各樣的緩存實現對象、布爾變量,代碼確實清晰、簡單了很多,小民對主管的崇敬之情又“泛濫”了起來。需要注意的是,這里的ImageCache類并不是小民原來的那個ImageCache,這次程序重構主管把它提取成一個圖片緩存的接口,用來抽象圖片緩存的功能。我們看看該接口的聲明:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ImageCache</span> {</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url);<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp); }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

ImageCache接口簡單定義了獲取、緩存圖片兩個函數,緩存的key是圖片的url,值是圖片本身。內存緩存、SD卡緩存、雙緩存都實現了該接口,我們看看這幾個緩存實現:

<code class="language-java hljs has-numbering"><span class="hljs-comment">// 內存緩存MemoryCache類</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MemoryCache</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ImageCache</span> {</span><span class="hljs-keyword">private</span> LruCache<String, Bitmap> mMemeryCache;<span class="hljs-keyword">public</span> <span class="hljs-title">MemoryCache</span>() {<span class="hljs-comment">// 初始化LRU緩存</span>}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {<span class="hljs-keyword">return</span> mMemeryCache.get(url);}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {mMemeryCache.put(url, bmp);} }<span class="hljs-comment">// SD卡緩存DiskCache類</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DiskCache</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ImageCache</span> {</span><span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span><span class="hljs-comment">/* 從本地文件中獲取該圖片 */</span>;}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {<span class="hljs-comment">// 將Bitmap寫入文件中</span>} }<span class="hljs-comment">// 雙緩存DoubleCache類</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DoubleCache</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ImageCache</span>{</span>ImageCache mMemoryCache = <span class="hljs-keyword">new</span> MemoryCache();ImageCache mDiskCache = <span class="hljs-keyword">new</span> DiskCache();<span class="hljs-comment">// 先從內存緩存中獲取圖片,如果沒有,再從SD卡中獲取</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {Bitmap bitmap = mMemoryCache.get(url);<span class="hljs-keyword">if</span> (bitmap == <span class="hljs-keyword">null</span>) {bitmap = mDiskCache.get(url);}<span class="hljs-keyword">return</span> bitmap;}<span class="hljs-comment">// 將圖片緩存到內存和SD卡中</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {mMemoryCache.put(url, bmp);mDiskCache.put(url, bmp);} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li></ul>

細心的朋友可能注意到了,ImageLoader類中增加了一個setImageCache(ImageCache cache)函數,用戶可以通過該函數設置緩存實現,也就是通常說的依賴注入。下面就看看用戶是如何設置緩存實現的:

<code class="language-java hljs has-numbering">ImageLoader imageLoader = <span class="hljs-keyword">new</span> ImageLoader() ;<span class="hljs-comment">// 使用內存緩存</span> imageLoader.setImageCache(<span class="hljs-keyword">new</span> MemoryCache());<span class="hljs-comment">// 使用SD卡緩存</span> imageLoader.setImageCache(<span class="hljs-keyword">new</span> DiskCache());<span class="hljs-comment">// 使用雙緩存</span> imageLoader.setImageCache(<span class="hljs-keyword">new</span> DoubleCache());<span class="hljs-comment">// 使用自定義的圖片緩存實現</span> imageLoader.setImageCache(<span class="hljs-keyword">new</span> ImageCache() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {<span class="hljs-comment">// 緩存圖片</span>}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url) {<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span><span class="hljs-comment">/*從緩存中獲取圖片*/</span>;}});</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

在上述代碼中,通過setImageCache(ImageCache cache)方法注入不同的緩存實現,這樣不僅能夠使ImageLoader更簡單、健壯,也使得ImageLoader的可擴展性、靈活性更高。MemoryCache、DiskCache、DoubleCache緩存圖片的具體實現完全不一樣,但是,它們的一個特點是都實現了ImageCache接口。當用戶需要自定義實現緩存策略時,只需要新建一個實現ImageCache接口的類,然后構造該類的對象,并且通過setImageCache(ImageCache cache)注入到ImageLoader中,這樣ImageLoader就實現了變化萬千的緩存策略,而擴展這些緩存策略并不會導致ImageLoader類的修改。經過這次重構,小民的ImageLoader已經基本算合格了。咦!這不就是主管說的開閉原則么!“軟件中的對象(類、模塊、函數等)應該對于擴展是開放的,但是對于修改是封閉的。而遵循開閉原則的重要手段應該是通過抽象……”小民細聲細語的念叨中,陷入了思索中……

開閉原則指導我們,當軟件需要變化時,應該盡量通過擴展的方式來實現變化,而不是通過修改已有的代碼來實現。這里的“應該盡量”4個字說明OCP原則并不是說絕對不可以修改原始類的,當我們嗅到原來的代碼“腐化氣味”時,應該盡早地重構,以使得代碼恢復到正常的“進化”軌道,而不是通過繼承等方式添加新的實現,這會導致類型的膨脹以及歷史遺留代碼的冗余。我們的開發過程中也沒有那么理想化的狀況,完全地不用修改原來的代碼,因此,在開發過程中需要自己結合具體情況進行考量,是通過修改舊代碼還是通過繼承使得軟件系統更穩定、更靈活,在保證去除“代碼腐化”的同時,也保證原有模塊的正確性。

3、構建擴展性更好的系統——里氏替換原則

里氏替換原則英文全稱是Liskov Substitution Principle,簡稱LSP。它的第一種定義是:如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程序P在所有的對象o1都代換成o2時,程序P的行為沒有發生變化,那么類型S是類型T的子類型。上面這種描述確實不太好理解,理論家有時候容易把問題抽象化,本來挺容易理解的事讓他們一概括就弄得拗口了。我們再看看另一個直截了當的定義。里氏替換原則第二種定義:所有引用基類的地方必須能透明地使用其子類的對象。

我們知道,面向對象的語言的三大特點是繼承、封裝、多態,里氏替換原則就是依賴于繼承、多態這兩大特性。里氏替換原則簡單來說就是,所有引用基類的地方必須能透明地使用其子類的對象。通俗點講,只要父類能出現的地方子類就可以出現,而且替換為子類也不會產生任何錯誤或異常,使用者可能根本就不需要知道是父類還是子類。但是,反過來就不行了,有子類出現的地方,父類未必就能適應。說了那么多,其實最終總結就兩個字:抽象。
小民為了深入地了解Android中的Window與View的關系特意寫了一個簡單示例,為了便于理解,我們先看如圖1-3所示。

▲圖1-3

我們看看具體的代碼:

<code class="language-java hljs has-numbering"><span class="hljs-comment">// 窗口類</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Window</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">show</span>(View child){child.draw();} }<span class="hljs-comment">// 建立視圖抽象,測量視圖的寬高為公用代碼,繪制交給具體的子類</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">View</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">draw</span>() ;<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">measure</span>(<span class="hljs-keyword">int</span> width, <span class="hljs-keyword">int</span> height){<span class="hljs-comment">// 測量視圖大小</span>} }<span class="hljs-comment">// 按鈕類的具體實現</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Button</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">View</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">draw</span>(){<span class="hljs-comment">// 繪制按鈕</span>} } <span class="hljs-comment">// TextView的具體實現</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TextView</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">View</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">draw</span>(){<span class="hljs-comment">// 繪制文本</span>} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul>

上述示例中,Window依賴于View,而View定義了一個視圖抽象,measure是各個子類共享的方法,子類通過覆寫View的draw方法實現具有各自特色的功能,在這里,這個功能就是繪制自身的內容。任何繼承自View類的子類都可以設置給show方法,也就我們所說的里氏替換。通過里氏替換,就可以自定義各式各樣、千變萬化的View,然后傳遞給Window,Window負責組織View,并且將View顯示到屏幕上。
里氏替換原則的核心原理是抽象,抽象又依賴于繼承這個特性,在OOP當中,繼承的優缺點都相當明顯。
優點如下:

  • (1)代碼重用,減少創建類的成本,每個子類都擁有父類的方法和屬性;
  • (2)子類與父類基本相似,但又與父類有所區別;
  • (3)提高代碼的可擴展性。

繼承的缺點:

  • (1)繼承是侵入性的,只要繼承就必須擁有父類的所有屬性和方法;
  • (2)可能造成子類代碼冗余、靈活性降低,因為子類必須擁有父類的屬性和方法。

事物總是具有兩面性,如何權衡利與弊都是需要根據具體場景來做出選擇并加以處理。里氏替換原則指導我們構建擴展性更好的軟件系統,我們還是接著上面的ImageLoader來做說明。
上文的圖1-2也很好地反應了里氏替換原則,即MemoryCache、DiskCache、DoubleCache都可以替換ImageCache的工作,并且能夠保證行為的正確性。ImageCache建立了獲取緩存圖片、保存緩存圖片的接口規范,MemoryCache等根據接口規范實現了相應的功能,用戶只需要在使用時指定具體的緩存對象就可以動態地替換ImageLoader中的緩存策略。這就使得ImageLoader的緩存系統具有了無線的可能性,也就是保證了可擴展性。

想象一個場景,當ImageLoader中的setImageCache(ImageCache cache)中的cache對象不能夠被子類所替換,那么用戶如何設置不同的緩存對象以及用戶如何自定義自己的緩存實現,通過1.3節中的useDiskCache方法嗎?顯然不是的,里氏替換原則就為這類問題提供了指導原則,也就是建立抽象,通過抽象建立規范,具體的實現在運行時替換掉抽象,保證系統的高擴展性、靈活性。開閉原則和里氏替換原則往往是生死相依、不棄不離的,通過里氏替換來達到對擴展開放,對修改關閉的效果。然而,這兩個原則都同時強調了一個OOP的重要特性——抽象,因此,在開發過程中運用抽象是走向代碼優化的重要一步。

4、 讓項目擁有變化的能力——依賴倒置原則

依賴倒置原則英文全稱是Dependence Inversion Principle,簡稱DIP。依賴反轉原則指代了一種特定的解耦形式,使得高層次的模塊不依賴于低層次的模塊的實現細節的目的,依賴模塊被顛倒了。這個概念有點不好理解,這到底是什么意思呢?
依賴倒置原則的幾個關鍵點:

  • (1)高層模塊不應該依賴低層模塊,兩者都應該依賴其抽象;
  • (2)抽象不應該依賴細節;
  • (3)細節應該依賴抽象。

在Java語言中,抽象就是指接口或抽象類,兩者都是不能直接被實例化的;細節就是實現類,實現接口或繼承抽象類而產生的類就是細節,其特點就是,可以直接被實例化,也就是可以加上一個關鍵字 new 產生一個對象。高層模塊就是調用端,低層模塊就是具體實現類。依賴倒置原則在 Java 語言中的表現就是:模塊間的依賴通過抽象發生,實現類之間不發生直接的依賴關系,其依賴關系是通過接口或抽象類產生的。這又是一個將理論抽象化的實例,其實一句話就可以概括:面向接口編程,或者說是面向抽象編程,這里的抽象指的是接口或者抽象類。面向接口編程是面向對象精髓之一,也就是上面兩節強調的抽象。

如果在類與類直接依賴于細節,那么它們之間就有直接的耦合,當具體實現需要變化時,意味著在這要同時修改依賴者的代碼,并且限制了系統的可擴展性。我們看1.3節的圖1-3中,ImageLoader直接依賴于MemoryCache,這個MemoryCache是一個具體實現,而不是一個抽象類或者接口。這導致了ImageLoader直接依賴了具體細節,當MemoryCache不能滿足ImageLoader而需要被其他緩存實現替換時,此時就必須修改ImageLoader的代碼,例如:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 內存緩存 ( 直接依賴于細節 )</span>MemoryCache mMemoryCache = <span class="hljs-keyword">new</span> MemoryCache();<span class="hljs-comment">// 加載圖片到ImageView中</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(String url, ImageView imageView) {Bitmap bmp = mMemoryCache.get(url);<span class="hljs-keyword">if</span> (bmp == <span class="hljs-keyword">null</span>) {downloadImage(url, imageView);} <span class="hljs-keyword">else</span> {imageView.setImageBitmap(bmp);}}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setImageCache</span>(MemoryCache cache) {mCache = cache ;}<span class="hljs-comment">// 代碼省略</span> }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>

隨著產品的升級,用戶發現MemoryCache已經不能滿足需求,用戶需要小民的ImageLoader可以將圖片同時緩存到內存和SD卡中,或者可以讓用戶自定義實現緩存。此時,我們的MemoryCache這個類名不僅不能夠表達內存緩存和SD卡緩存的意義,也不能夠滿足功能。另外,用戶需要自定義緩存實現時還必須繼承自MemoryCache,而用戶的緩存實現可不一定與內存緩存有關,這在命名上的限制也讓用戶體驗不好。重構的時候到了!小民的第一種方案是將MemoryCache修改為DoubleCache,然后在DoubleCache中實現具體的緩存功能。我們需要將ImageLoader修改如下:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 雙緩存 ( 直接依賴于細節 )</span>DoubleCache mCache = <span class="hljs-keyword">new</span> DoubleCache();<span class="hljs-comment">// 加載圖片到ImageView中</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(String url, ImageView imageView) {Bitmap bmp = mCache.get(url);<span class="hljs-keyword">if</span> (bmp == <span class="hljs-keyword">null</span>) {<span class="hljs-comment">// 異步下載圖片</span>downloadImageAsync(url, imageView);} <span class="hljs-keyword">else</span> {imageView.setImageBitmap(bmp);}}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setImageCache</span>(DoubleCache cache) {mCache = cache ;}<span class="hljs-comment">// 代碼省略</span> }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>

我們將MemoryCache修改成DoubleCache,然后修改了ImageLoader中緩存類的具體實現,輕輕松松就滿足了用戶需求。等等!這不還是依賴于具體的實現類(DoubleCache)嗎?當用戶的需求再次變化時,我們又要通過修改緩存實現類和ImageLoader代碼來實現?修改原有代碼不是違反了1.3節中的開閉原則嗎?小民突然醒悟了過來,低下頭思索著如何才能讓緩存系統更靈活、擁抱變化……

當然,這些都是在主管給出圖1-2(1.3節)以及相應的代碼之前,小民體驗的煎熬過程。既然是這樣,那顯然主管給出的解決方案就能夠讓緩存系統更加靈活。一句話概括起來就是:依賴抽象,而不依賴具體實現。針對于圖片緩存,主管建立的ImageCache抽象,該抽象中增加了get和put方法用以實現圖片的存取。每種緩存實現都必須實現這個接口,并且實現自己的存取方法。當用戶需要使用不同的緩存實現時,直接通過依賴注入即可,保證了系統的靈活性。我們再來簡單回顧一下相關代碼:

ImageCache緩存抽象:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ImageCache</span> {</span><span class="hljs-keyword">public</span> Bitmap <span class="hljs-title">get</span>(String url);<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp); }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

ImageLoader類:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span> {</span><span class="hljs-comment">// 圖片緩存類,依賴于抽象,并且有一個默認的實現</span>ImageCache mCache = <span class="hljs-keyword">new</span> MemoryCache();<span class="hljs-comment">// 加載圖片</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">displayImage</span>(String url, ImageView imageView) {Bitmap bmp = mCache.get(url);<span class="hljs-keyword">if</span> (bmp == <span class="hljs-keyword">null</span>) {<span class="hljs-comment">// 異步加載圖片</span>downloadImageAsync(url, imageView);} <span class="hljs-keyword">else</span> {imageView.setImageBitmap(bmp);}}<span class="hljs-javadoc">/*** 設置緩存策略,依賴于抽象*/</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setImageCache</span>(ImageCache cache) {mCache = cache;}<span class="hljs-comment">// 代碼省略</span> }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li></ul>

在這里,我們建立了ImageCache抽象,并且讓ImageLoader依賴于抽象而不是具體細節。當需求發生變更時,小民只需要實現ImageCahce類或者繼承其他已有的ImageCache子類完成相應的緩存功能,然后將具體的實現注入到ImageLoader即可實現緩存功能的替換,這就保證了緩存系統的高可擴展性,擁有了擁抱變化的能力,而這一切的基本指導原則就是我們的依賴倒置原則。從上述幾節中我們發現,要想讓我們的系統更為靈活,抽象似乎成了我們唯一的手段。

5、系統有更高的靈活性——接口隔離原則

接口隔離原則英文全稱是InterfaceSegregation Principles,簡稱ISP。它的定義是:客戶端不應該依賴它不需要的接口。另一種定義是:類間的依賴關系應該建立在最小的接口上。接口隔離原則將非常龐大、臃腫的接口拆分成為更小的和更具體的接口,這樣客戶將會只需要知道他們感興趣的方法。接口隔離原則的目的是系統解開耦合,從而容易重構、更改和重新部署。

接口隔離原則說白了就是,讓客戶端依賴的接口盡可能地小,這樣說可能還是有點抽象,我們還是以一個示例來說明一下。在此之前我們來說一個場景,在Java 6以及之前的JDK版本,有一個非常討厭的問題,那就是在使用了OutputStream或者其他可關閉的對象之后,我們必須保證它們最終被關閉了,我們的SD卡緩存類中就有這樣的代碼:

<code class="language-java hljs has-numbering"><span class="hljs-comment">// 將圖片緩存到內存中</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {FileOutputStream fileOutputStream = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {fileOutputStream = <span class="hljs-keyword">new</span> FileOutputStream(cacheDir + url);bmp.compress(CompressFormat.PNG, <span class="hljs-number">100</span>, fileOutputStream);} <span class="hljs-keyword">catch</span> (FileNotFoundException e) {e.printStackTrace();} <span class="hljs-keyword">finally</span> {<span class="hljs-keyword">if</span> (fileOutputStream != <span class="hljs-keyword">null</span>) {<span class="hljs-keyword">try</span> {fileOutputStream.close();} <span class="hljs-keyword">catch</span> (IOException e) {e.printStackTrace();}} <span class="hljs-comment">// end if</span>} <span class="hljs-comment">// end if finally</span> }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>

我們看到的這段代碼可讀性非常差,各種try…catch嵌套,都是些簡單的代碼,但是會嚴重影響代碼的可讀性,并且多層級的大括號很容易將代碼寫到錯誤的層級中。大家應該對這類代碼也非常反感,那我們看看如何解決這類問題。
我們可能知道Java中有一個Closeable接口,該接口標識了一個可關閉的對象,它只有一個close方法,如圖1-4所示。
我們要講的FileOutputStream類就實現了這個接口,我們從圖1-4中可以看到,還有一百多個類實現了Closeable這個接口,這意味著,在關閉這一百多個類型的對象時,都需要寫出像put方法中finally代碼段那樣的代碼。這還了得!你能忍,反正小民是忍不了的!于是小民打算要發揮他的聰明才智解決這個問題,既然都是實現了Closeable接口,那只要我建一個方法統一來關閉這些對象不就可以了么?說干就干,于是小民寫下來如下的工具類:

▲圖1-4

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CloseUtils</span> {</span>Private CloseUtils() { }<span class="hljs-javadoc">/*** 關閉Closeable對象*<span class="hljs-javadoctag"> @param</span> closeable*/</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">closeQuietly</span>(Closeable closeable) {<span class="hljs-keyword">if</span> (<span class="hljs-keyword">null</span> != closeable) {<span class="hljs-keyword">try</span> {closeable.close();} <span class="hljs-keyword">catch</span> (IOException e) {e.printStackTrace();}}} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>

我們再看看把這段代碼運用到上述的put方法中的效果如何:

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {FileOutputStream fileOutputStream = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {fileOutputStream = <span class="hljs-keyword">new</span> FileOutputStream(cacheDir + url);bmp.compress(CompressFormat.PNG, <span class="hljs-number">100</span>, fileOutputStream);} <span class="hljs-keyword">catch</span> (FileNotFoundException e) {e.printStackTrace();} <span class="hljs-keyword">final</span> ly {CloseUtils.closeQuietly(fileOutputStream);} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

代碼簡潔了很多!而且這個closeQuietly方法可以運用到各類可關閉的對象中,保證了代碼的重用性。CloseUtils的closeQuietly方法的基本原理就是依賴于Closeable抽象而不是具體實現(這不是1.4節中的依賴倒置原則么),并且建立在最小化依賴原則的基礎,它只需要知道這個對象是可關閉,其他的一概不關心,也就是這里的接口隔離原則。

試想一下,如果在只是需要關閉一個對象時,它卻暴露出了其他的接口函數,比如OutputStream的write方法,這就使得更多的細節暴露在客戶端代碼面前,不僅沒有很好地隱藏實現,還增加了接口的使用難度。而通過Closeable接口將可關閉的對象抽象起來,這樣只需要客戶端依賴于Closeable就可以對客戶端隱藏其他的接口信息,客戶端代碼只需要知道這個對象可關閉(只可調用close方法)即可。小民ImageLoader中的ImageCache就是接口隔離原則的運用,ImageLoader只需要知道該緩存對象有存、取緩存圖片的接口即可,其他的一概不管,這就使得緩存功能的具體實現對ImageLoader具體的隱藏。這就是用最小化接口隔離了實現類的細節,也促使我們將龐大的接口拆分到更細粒度的接口當中,這使得我們的系統具有更低的耦合性,更高的靈活性。

Bob大叔(Robert C Martin)在21世紀早期將單一職責、開閉原則、里氏替換、接口隔離以及依賴倒置(也稱為依賴反轉)5個原則定義為SOLID原則,指代了面向對象編程的5個基本原則。當這些原則被一起應用時,它們使得一個軟件系統更清晰、簡單、最大程度地擁抱變化。SOLID被典型地應用在測試驅動開發上,并且是敏捷開發以及自適應軟件開發基本原則的重要組成部分。在經過第1.1~1.5節的學習之后,我們發現這幾大原則最終就可以化為這幾個關鍵詞:抽象、單一職責、最小化。那么在實際開發過程中如何權衡、實踐這些原則,是大家需要在實踐中多思考與領悟,正所謂”學而不思則罔,思而不學則殆”,只有不斷地學習、實踐、思考,才能夠在積累的過程有一個質的飛越。

6、更好的可擴展性——迪米特原則

迪米特原則英文全稱為Law of Demeter,簡稱LOD,也稱為最少知識原則(Least Knowledge Principle)。雖然名字不同,但描述的是同一個原則:一個對象應該對其他對象有最少的了解。通俗地講,一個類應該對自己需要耦合或調用的類知道得最少,類的內部如何實現、如何復雜都與調用者或者依賴者沒關系,調用者或者依賴者只需要知道他需要的方法即可,其他的我一概不關心。類與類之間的關系越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大。

迪米特法則還有一個英文解釋是:Only talk to your immedate friends,翻譯過來就是:只與直接的朋友通信。什么叫做直接的朋友呢?每個對象都必然會與其他對象有耦合關系,兩個對象之間的耦合就成為朋友關系,這種關系的類型有很多,例如組合、聚合、依賴等。

光說不練很抽象吶,下面我們就以租房為例來講講迪米特原則。
“北漂”的同學比較了解,在北京租房絕大多數都是通過中介找房。我們設定的情境為:我只要求房間的面積和租金,其他的一概不管,中介將符合我要求的房子提供給我就可以。下面我們看看這個示例:

<code class="language-java hljs has-numbering"><span class="hljs-javadoc">/*** 房間*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Room</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> area;<span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> price;<span class="hljs-keyword">public</span> <span class="hljs-title">Room</span>(<span class="hljs-keyword">float</span> area, <span class="hljs-keyword">float</span> price) {<span class="hljs-keyword">this</span>.area = area;<span class="hljs-keyword">this</span>.price = price;}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span>() {<span class="hljs-keyword">return</span> <span class="hljs-string">"Room [area="</span> + area + <span class="hljs-string">", price="</span> + price + <span class="hljs-string">"]"</span>;}}<span class="hljs-javadoc">/*** 中介*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mediator</span> {</span>List<Room> mRooms = <span class="hljs-keyword">new</span> ArrayList<Room>();<span class="hljs-keyword">public</span> <span class="hljs-title">Mediator</span>() {<span class="hljs-keyword">for</span> (inti = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {mRooms.add(<span class="hljs-keyword">new</span> Room(<span class="hljs-number">14</span> + i, (<span class="hljs-number">14</span> + i) * <span class="hljs-number">150</span>));}}<span class="hljs-keyword">public</span> List<Room><span class="hljs-title">getAllRooms</span>() {<span class="hljs-keyword">return</span> mRooms;} }<span class="hljs-javadoc">/*** 租戶*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tenant</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> roomArea;<span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> roomPrice;<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">float</span> diffPrice = <span class="hljs-number">100.0001</span>f;<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">float</span> diffArea = <span class="hljs-number">0.00001</span>f;<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">rentRoom</span>(Mediator mediator) {List<Room>rooms = mediator.getAllRooms();<span class="hljs-keyword">for</span> (Room room : rooms) {<span class="hljs-keyword">if</span> (isSuitable(room)) {System.out.println(<span class="hljs-string">"租到房間啦! "</span> + room);<span class="hljs-keyword">break</span>;}}}<span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isSuitable</span>(Room room) {<span class="hljs-keyword">return</span> Math.abs(room.price - roomPrice) < diffPrice&&Math.abs(room.area - roomArea) < diffArea;} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li></ul>

從上面的代碼中可以看到,Tenant不僅依賴了Mediator類,還需要頻繁地與Room類打交道。租戶類的要求只是通過中介找到一間適合自己的房間罷了,如果把這些檢測條件都放在Tenant類中,那么中介類的功能就被弱化,而且導致Tenant與Room的耦合較高,因為Tenant必須知道許多關于Room的細節。當Room變化時Tenant也必須跟著變化。Tenant又與Mediator耦合,就導致了糾纏不清的關系。這個時候就需要我們分清誰才是我們真正的“朋友”,在我們所設定的情況下,顯然是Mediator(雖然現實生活中不是這樣的)。上述代碼的結構如圖1-5所示。

▲圖1-5

既然是耦合太嚴重,那我們就只能解耦了,首先要明確地是,我們只和我們的朋友通信,這里就是指Mediator對象。必須將Room相關的操作從Tenant中移除,而這些操作案例應該屬于Mediator,我們進行如下重構:

<code class="language-java hljs has-numbering"><span class="hljs-javadoc">/*** 中介*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mediator</span> {</span>List<Room> mRooms = <span class="hljs-keyword">new</span> ArrayList<Room>();<span class="hljs-keyword">public</span> <span class="hljs-title">Mediator</span>() {<span class="hljs-keyword">for</span> (inti = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {mRooms.add(<span class="hljs-keyword">new</span> Room(<span class="hljs-number">14</span> + i, (<span class="hljs-number">14</span> + i) * <span class="hljs-number">150</span>));}}<span class="hljs-keyword">public</span> Room <span class="hljs-title">rentOut</span>(<span class="hljs-keyword">float</span> area, <span class="hljs-keyword">float</span> price) {<span class="hljs-keyword">for</span> (Room room : mRooms) {<span class="hljs-keyword">if</span> (isSuitable(area, price, room)) {<span class="hljs-keyword">return</span> room;}}<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;}<span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isSuitable</span>(<span class="hljs-keyword">float</span> area, <span class="hljs-keyword">float</span> price, Room room) {<span class="hljs-keyword">return</span> Math.abs(room.price - price) < Tenant.diffPrice&& Math.abs(room.area - area) < Tenant.diffPrice;} }<span class="hljs-javadoc">/*** 租戶*/</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tenant</span> {</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> roomArea;<span class="hljs-keyword">public</span> <span class="hljs-keyword">float</span> roomPrice;<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">float</span> diffPrice = <span class="hljs-number">100.0001</span>f;<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">float</span> diffArea = <span class="hljs-number">0.00001</span>f;<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">rentRoom</span>(Mediator mediator) {System.out.println(<span class="hljs-string">"租到房啦 "</span> + mediator.rentOut(roomArea, roomPrice));} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li></ul>

重構后的結構圖如圖1-6所示。

▲圖1-6

只是將對于Room的判定操作移到了Mediator類中,這本應該是Mediator的職責,他們根據租戶設定的條件查找符合要求的房子,并且將結果交給租戶就可以了。租戶并不需要知道太多關于Room的細節,比如與房東簽合同、房東的房產證是不是真的、房內的設施壞了之后我要找誰維修等,當我們通過我們的“朋友”中介租了房之后,所有的事情我們都通過與中介溝通就好了,房東、維修師傅等這些角色并不是我們直接的“朋友”。“只與直接的朋友通信”這簡單的幾個字就能夠將我們從亂七八糟的關系網中抽離出來,使我們的耦合度更低、穩定性更好。
通過上述示例以及小民的后續思考,迪米特原則這把利劍在小民的手中已經舞得風生水起。就拿sd卡緩存來說吧,ImageCache就是用戶的直接朋友,而SD卡緩存內部卻是使用了jake wharton的DiskLruCache實現,這個DiskLruCache就不屬于用戶的直接朋友了,因此,用戶完全不需要知道它的存在,用戶只需要與ImageCache對象打交道即可。例如將圖片存到SD卡中的代碼如下。

<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap value) {DiskLruCache.Editor editor = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {<span class="hljs-comment">// 如果沒有找到對應的緩存,則準備從網絡上請求數據,并寫入緩存</span>editor = mDiskLruCache.edit(url);<span class="hljs-keyword">if</span> (editor != <span class="hljs-keyword">null</span>) {OutputStream outputStream = editor.newOutputStream(<span class="hljs-number">0</span>);<span class="hljs-keyword">if</span> (writeBitmapToDisk(value, outputStream)) {<span class="hljs-comment">// 寫入disk緩存</span>editor.commit();} <span class="hljs-keyword">else</span> {editor.abort();}CloseUtils.closeQuietly(outputStream);}} <span class="hljs-keyword">catch</span> (IOException e) {e.printStackTrace();} }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>

用戶在使用SD卡緩存時,根本不知曉DiskLruCache的實現,這就很好地對用戶隱藏了具體實現。當小民已經“牛”到可以自己完成SD卡的rul實現時,他就可以隨心所欲的替換掉jake wharton的DiskLruCache。小民的代碼大體如下:

<code class="language-java hljs has-numbering"><span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">put</span>(String url, Bitmap bmp) {<span class="hljs-comment">// 將Bitmap寫入文件中</span>FileOutputStream fos = <span class="hljs-keyword">null</span>;<span class="hljs-keyword">try</span> {<span class="hljs-comment">// 構建圖片的存儲路徑 ( 省略了對url取md5)</span>fos = <span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-string">"sdcard/cache/"</span> + imageUrl2MD5(url));bmp.compress(CompressFormat.JPEG, <span class="hljs-number">100</span>, fos);} <span class="hljs-keyword">catch</span> (FileNotFoundException e) {e.printStackTrace();} <span class="hljs-keyword">finally</span> {<span class="hljs-keyword">if</span> ( fos != <span class="hljs-keyword">null</span> ) {<span class="hljs-keyword">try</span> {fos.close();} <span class="hljs-keyword">catch</span> (IOException e) {e.printStackTrace();}}} <span class="hljs-comment">// end if finally</span> }</code><ul class="pre-numbering" style="display: block;"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

SD卡緩存的具體實現雖然被替換了,但用戶根本不會感知到。因為用戶根本不知道DiskLruCache的存在,他們沒有與DiskLruCache進行通信,他們只認識直接“朋友”ImageCache,ImageCache將一切細節隱藏在了直接“朋友”的外衣之下,使得系統具有更低的耦合性和更好的可擴展性。

7、總結

在應用開發過程中,最難的不是完成應用的開發工作,而是在后續的升級、維護過程中讓應用系統能夠擁抱變化。擁抱變化也就意味著在滿足需求且不破壞系統穩定性的前提下保持高可擴展性、高內聚、低耦合,在經歷了各版本的變更之后依然保持清晰、靈活、穩定的系統架構。當然,這是一個比較理想的情況,但我們必須要朝著這個方向去努力,那么遵循面向對象六大原則就是我們走向靈活軟件之路所邁出的第一步。

總結

以上是生活随笔為你收集整理的代码原则的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

亚洲综合精品香蕉久久网 | 国产无遮挡又黄又爽又色 | 中文字幕无码免费久久9一区9 | 亚洲精品综合一区二区三区在线 | 国产三级久久久精品麻豆三级 | 亚洲熟妇色xxxxx亚洲 | 国产又爽又猛又粗的视频a片 | 啦啦啦www在线观看免费视频 | 日日鲁鲁鲁夜夜爽爽狠狠 | 激情爆乳一区二区三区 | 高潮毛片无遮挡高清免费 | 国产精品高潮呻吟av久久4虎 | 午夜熟女插插xx免费视频 | 亚洲另类伦春色综合小说 | 国内综合精品午夜久久资源 | 欧美日本日韩 | 久久久久se色偷偷亚洲精品av | aa片在线观看视频在线播放 | 中文字幕无码av波多野吉衣 | 国产香蕉尹人视频在线 | 日韩欧美群交p片內射中文 | 国产三级久久久精品麻豆三级 | 久久精品国产亚洲精品 | 麻花豆传媒剧国产免费mv在线 | 久久久成人毛片无码 | 国产真实夫妇视频 | 国产成人精品视频ⅴa片软件竹菊 | 国产精品视频免费播放 | 亚洲s色大片在线观看 | 波多野结衣高清一区二区三区 | 沈阳熟女露脸对白视频 | 国产人妖乱国产精品人妖 | 日本精品高清一区二区 | 久久婷婷五月综合色国产香蕉 | 亚洲熟妇自偷自拍另类 | 2019午夜福利不卡片在线 | 天海翼激烈高潮到腰振不止 | 少妇无码吹潮 | 精品国偷自产在线视频 | 18禁黄网站男男禁片免费观看 | 免费中文字幕日韩欧美 | 丰满岳乱妇在线观看中字无码 | 真人与拘做受免费视频 | 成人无码视频在线观看网站 | 欧美熟妇另类久久久久久多毛 | 亚洲а∨天堂久久精品2021 | 一个人看的www免费视频在线观看 | 九九在线中文字幕无码 | 玩弄人妻少妇500系列视频 | 中文字幕乱码亚洲无线三区 | 久久99久久99精品中文字幕 | 动漫av网站免费观看 | 日韩少妇白浆无码系列 | 亚洲精品一区三区三区在线观看 | v一区无码内射国产 | 亚洲无人区午夜福利码高清完整版 | 亚洲人亚洲人成电影网站色 | 波多野结衣av在线观看 | 国产人成高清在线视频99最全资源 | 久久久久久久女国产乱让韩 | 久久久国产精品无码免费专区 | 久久综合给久久狠狠97色 | 亚洲 a v无 码免 费 成 人 a v | 久久无码人妻影院 | 国产va免费精品观看 | 国产综合在线观看 | 午夜嘿嘿嘿影院 | 性史性农村dvd毛片 | 香蕉久久久久久av成人 | 东京无码熟妇人妻av在线网址 | 亚洲 a v无 码免 费 成 人 a v | 东京热男人av天堂 | 亚洲第一无码av无码专区 | 在线播放亚洲第一字幕 | 国产人妻久久精品二区三区老狼 | 97久久精品无码一区二区 | 国产精品久久国产精品99 | 精品欧洲av无码一区二区三区 | 亚洲自偷精品视频自拍 | 久久人妻内射无码一区三区 | 午夜精品一区二区三区在线观看 | 高潮毛片无遮挡高清免费视频 | 国产极品美女高潮无套在线观看 | 亚洲色成人中文字幕网站 | 国产成人av免费观看 | 亚洲一区二区三区播放 | 国产精品香蕉在线观看 | 亚洲国产精品无码久久久久高潮 | 精品国偷自产在线视频 | 久久成人a毛片免费观看网站 | 真人与拘做受免费视频 | 任你躁国产自任一区二区三区 | 捆绑白丝粉色jk震动捧喷白浆 | 中文字幕中文有码在线 | 久久久成人毛片无码 | 人妻中文无码久热丝袜 | 在线观看国产一区二区三区 | 人人爽人人澡人人人妻 | 在教室伦流澡到高潮hnp视频 | 熟妇女人妻丰满少妇中文字幕 | 色老头在线一区二区三区 | 欧美人与物videos另类 | 99在线 | 亚洲 | 一个人看的视频www在线 | 成人女人看片免费视频放人 | 久久久精品456亚洲影院 | 国产精品久久精品三级 | 欧美日韩亚洲国产精品 | 一二三四社区在线中文视频 | 精品国产一区av天美传媒 | 欧美放荡的少妇 | 久久久中文久久久无码 | 又色又爽又黄的美女裸体网站 | 国产在热线精品视频 | 奇米影视888欧美在线观看 | 午夜福利不卡在线视频 | 最近免费中文字幕中文高清百度 | 思思久久99热只有频精品66 | 樱花草在线社区www | 一本大道久久东京热无码av | 激情亚洲一区国产精品 | 内射老妇bbwx0c0ck | 老熟妇乱子伦牲交视频 | 亚洲日韩av一区二区三区中文 | 久久精品国产99久久6动漫 | 99精品无人区乱码1区2区3区 | 无码乱肉视频免费大全合集 | 最新国产乱人伦偷精品免费网站 | 免费网站看v片在线18禁无码 | 国产亚洲视频中文字幕97精品 | 欧美熟妇另类久久久久久不卡 | 夜先锋av资源网站 | 亚洲色大成网站www | 九一九色国产 | 天干天干啦夜天干天2017 | 日本丰满护士爆乳xxxx | 55夜色66夜色国产精品视频 | 国产精品久久久久久无码 | 欧美日韩视频无码一区二区三 | 无码人妻黑人中文字幕 | 在线观看国产午夜福利片 | 精品欧美一区二区三区久久久 | 成在人线av无码免费 | 熟妇人妻激情偷爽文 | 亚洲色无码一区二区三区 | 蜜桃无码一区二区三区 | 精品国精品国产自在久国产87 | 亚洲成色www久久网站 | 国产亚洲精品久久久闺蜜 | 亚洲经典千人经典日产 | 少妇被黑人到高潮喷出白浆 | 精品熟女少妇av免费观看 | 亚洲色无码一区二区三区 | 伊人久久大香线蕉亚洲 | 欧美国产日韩久久mv | 中文字幕无码视频专区 | 福利一区二区三区视频在线观看 | 亚洲国产成人av在线观看 | 久久久久久亚洲精品a片成人 | 久久久久99精品成人片 | 风流少妇按摩来高潮 | 最新国产乱人伦偷精品免费网站 | 日韩少妇白浆无码系列 | 狠狠色欧美亚洲狠狠色www | 久久精品国产99精品亚洲 | 99精品国产综合久久久久五月天 | 成人无码精品1区2区3区免费看 | 成年美女黄网站色大免费全看 | 成人性做爰aaa片免费看 | 国产午夜视频在线观看 | 国内精品九九久久久精品 | 国产精品久久久 | 久久精品国产一区二区三区 | 妺妺窝人体色www婷婷 | 午夜嘿嘿嘿影院 | 国产亚洲欧美日韩亚洲中文色 | 久久综合给久久狠狠97色 | 小sao货水好多真紧h无码视频 | 色爱情人网站 | 大色综合色综合网站 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产成人亚洲综合无码 | 日产精品99久久久久久 | 中文字幕乱码人妻无码久久 | 国产亚洲日韩欧美另类第八页 | 77777熟女视频在线观看 а天堂中文在线官网 | 强奷人妻日本中文字幕 | 18无码粉嫩小泬无套在线观看 | 国模大胆一区二区三区 | 中文字幕乱码亚洲无线三区 | 最新国产乱人伦偷精品免费网站 | 97se亚洲精品一区 | 图片区 小说区 区 亚洲五月 | 国产女主播喷水视频在线观看 | 久久午夜无码鲁丝片 | 亚洲第一无码av无码专区 | 一区二区三区乱码在线 | 欧洲 | 国语精品一区二区三区 | 色五月丁香五月综合五月 | 搡女人真爽免费视频大全 | 亚洲色大成网站www | 久久99国产综合精品 | 天天躁日日躁狠狠躁免费麻豆 | 亚洲高清偷拍一区二区三区 | 夜夜夜高潮夜夜爽夜夜爰爰 | 老司机亚洲精品影院无码 | 久久99国产综合精品 | 麻豆果冻传媒2021精品传媒一区下载 | 色欲人妻aaaaaaa无码 | 99久久无码一区人妻 | 久久久www成人免费毛片 | 老头边吃奶边弄进去呻吟 | 狠狠亚洲超碰狼人久久 | 亚洲国产成人av在线观看 | 日本高清一区免费中文视频 | 精品国产福利一区二区 | 国产人妻人伦精品 | 国产精品美女久久久久av爽李琼 | 鲁大师影院在线观看 | 成人免费视频视频在线观看 免费 | 日本丰满熟妇videos | 亚洲男人av香蕉爽爽爽爽 | 中文精品久久久久人妻不卡 | 欧美熟妇另类久久久久久不卡 | 久久无码中文字幕免费影院蜜桃 | 日日夜夜撸啊撸 | 桃花色综合影院 | 色老头在线一区二区三区 | 无套内谢的新婚少妇国语播放 | 99视频精品全部免费免费观看 | 久久国产精品萌白酱免费 | 在线视频网站www色 | 国产欧美亚洲精品a | 精品久久久久久亚洲精品 | 国产精品久久久久久亚洲影视内衣 | 久久无码专区国产精品s | 18精品久久久无码午夜福利 | 亚洲天堂2017无码 | 5858s亚洲色大成网站www | 欧美性猛交xxxx富婆 | 国产亚洲欧美在线专区 | 巨爆乳无码视频在线观看 | 97精品国产97久久久久久免费 | 国产乱子伦视频在线播放 | 亚洲人成无码网www | 女人被男人躁得好爽免费视频 | 亚洲日本va中文字幕 | 亚洲精品一区二区三区婷婷月 | 久久婷婷五月综合色国产香蕉 | 欧美熟妇另类久久久久久不卡 | 夜夜高潮次次欢爽av女 | 国产 精品 自在自线 | 激情国产av做激情国产爱 | 国产精品内射视频免费 | 国产97在线 | 亚洲 | aa片在线观看视频在线播放 | 日韩少妇内射免费播放 | 日本熟妇大屁股人妻 | 国产午夜精品一区二区三区嫩草 | 国产精品久久久久影院嫩草 | 人妻少妇被猛烈进入中文字幕 | 免费国产成人高清在线观看网站 | 色综合天天综合狠狠爱 | 亚洲综合在线一区二区三区 | 色一情一乱一伦一区二区三欧美 | 999久久久国产精品消防器材 | 成人一区二区免费视频 | 久久久久久久久蜜桃 | 人妻无码αv中文字幕久久琪琪布 | 国产午夜无码精品免费看 | 大屁股大乳丰满人妻 | 一本久道久久综合婷婷五月 | 波多野结衣高清一区二区三区 | 久久精品国产99久久6动漫 | 亚洲国产欧美国产综合一区 | 国产9 9在线 | 中文 | 久久久久久a亚洲欧洲av冫 | 国产精品二区一区二区aⅴ污介绍 | 精品乱子伦一区二区三区 | 成熟妇人a片免费看网站 | 色综合久久久久综合一本到桃花网 | 国语精品一区二区三区 | 国产高清不卡无码视频 | 国产情侣作爱视频免费观看 | 麻豆国产人妻欲求不满谁演的 | 任你躁在线精品免费 | 亚洲精品欧美二区三区中文字幕 | www国产亚洲精品久久网站 | 伊人久久大香线蕉亚洲 | 又粗又大又硬又长又爽 | 在线观看免费人成视频 | 日韩av无码一区二区三区不卡 | 婷婷六月久久综合丁香 | 牲欲强的熟妇农村老妇女视频 | 日韩av无码中文无码电影 | 樱花草在线社区www | 国产亚洲精品久久久久久大师 | 欧美激情一区二区三区成人 | 欧美freesex黑人又粗又大 | 精品国产aⅴ无码一区二区 | 国产乡下妇女做爰 | 性色av无码免费一区二区三区 | 综合激情五月综合激情五月激情1 | 好男人www社区 | 亚洲码国产精品高潮在线 | 美女张开腿让人桶 | 亚洲成av人片天堂网无码】 | 色一情一乱一伦一视频免费看 | 国产精品美女久久久网av | 久久伊人色av天堂九九小黄鸭 | 国产av一区二区精品久久凹凸 | 又大又紧又粉嫩18p少妇 | 亚洲国产精品成人久久蜜臀 | 亚洲日韩av片在线观看 | 欧美喷潮久久久xxxxx | 国产精品久久国产三级国 | 天天躁夜夜躁狠狠是什么心态 | 国产亲子乱弄免费视频 | 日本乱偷人妻中文字幕 | 激情亚洲一区国产精品 | 亚洲精品国偷拍自产在线麻豆 | 乌克兰少妇xxxx做受 | 国产又爽又猛又粗的视频a片 | 亚洲综合另类小说色区 | 天堂а√在线地址中文在线 | 免费观看激色视频网站 | 国产手机在线αⅴ片无码观看 | 国语精品一区二区三区 | 大肉大捧一进一出好爽视频 | 捆绑白丝粉色jk震动捧喷白浆 | 国精产品一品二品国精品69xx | 亚洲精品久久久久久一区二区 | 网友自拍区视频精品 | 内射白嫩少妇超碰 | 国产精品无套呻吟在线 | 少妇被粗大的猛进出69影院 | 国产人妻人伦精品 | 又大又紧又粉嫩18p少妇 | 久久国内精品自在自线 | 国产精品第一区揄拍无码 | 网友自拍区视频精品 | 国产精品久久久久久亚洲影视内衣 | 亚洲の无码国产の无码步美 | 人妻无码αv中文字幕久久琪琪布 | 麻豆av传媒蜜桃天美传媒 | 三级4级全黄60分钟 | 亚洲精品中文字幕乱码 | 樱花草在线播放免费中文 | 红桃av一区二区三区在线无码av | 色综合久久久久综合一本到桃花网 | 熟妇人妻无码xxx视频 | 亚洲日本va中文字幕 | 国产精品高潮呻吟av久久 | 欧美 日韩 人妻 高清 中文 | 性色欲网站人妻丰满中文久久不卡 | 乱码av麻豆丝袜熟女系列 | 18精品久久久无码午夜福利 | 国产suv精品一区二区五 | 无码国产色欲xxxxx视频 | 国产人妻大战黑人第1集 | 久久这里只有精品视频9 | 久久精品国产大片免费观看 | 中文字幕乱码人妻二区三区 | 亚洲啪av永久无码精品放毛片 | 久久亚洲a片com人成 | 两性色午夜视频免费播放 | 久久97精品久久久久久久不卡 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 成熟人妻av无码专区 | 欧美性生交xxxxx久久久 | 欧美 日韩 亚洲 在线 | 欧美日韩一区二区免费视频 | 强奷人妻日本中文字幕 | 国产无套内射久久久国产 | 亚洲一区二区三区四区 | 国产精品久久久一区二区三区 | 内射老妇bbwx0c0ck | 精品国产一区二区三区四区 | 久久精品女人天堂av免费观看 | 欧美喷潮久久久xxxxx | 激情国产av做激情国产爱 | 亚洲无人区午夜福利码高清完整版 | 女高中生第一次破苞av | 人妻少妇精品视频专区 | 亚洲国精产品一二二线 | 玩弄人妻少妇500系列视频 | 中文字幕日韩精品一区二区三区 | 伊人久久婷婷五月综合97色 | 99久久无码一区人妻 | 2020久久香蕉国产线看观看 | 欧美人与物videos另类 | yw尤物av无码国产在线观看 | 乱人伦人妻中文字幕无码久久网 | 99re在线播放 | 强开小婷嫩苞又嫩又紧视频 | 狂野欧美性猛xxxx乱大交 | 激情综合激情五月俺也去 | 久久国产自偷自偷免费一区调 | 在线亚洲高清揄拍自拍一品区 | 麻豆精品国产精华精华液好用吗 | 一本一道久久综合久久 | 日本xxxx色视频在线观看免费 | 国产特级毛片aaaaaa高潮流水 | 国产乱人无码伦av在线a | 老熟妇乱子伦牲交视频 | 日本熟妇人妻xxxxx人hd | 中文字幕av日韩精品一区二区 | av无码电影一区二区三区 | 亚洲乱码国产乱码精品精 | 永久免费精品精品永久-夜色 | 最近免费中文字幕中文高清百度 | 国精产品一品二品国精品69xx | 88国产精品欧美一区二区三区 | 亚洲国产高清在线观看视频 | 日本www一道久久久免费榴莲 | 国产欧美熟妇另类久久久 | 亚洲国产成人av在线观看 | 性啪啪chinese东北女人 | 亚洲最大成人网站 | 清纯唯美经典一区二区 | 老熟妇仑乱视频一区二区 | 日韩人妻少妇一区二区三区 | 在线播放免费人成毛片乱码 | 色爱情人网站 | 亚洲精品一区二区三区在线观看 | 中文字幕无码视频专区 | 国产av无码专区亚洲a∨毛片 | 99er热精品视频 | 久久久精品成人免费观看 | 偷窥日本少妇撒尿chinese | 国产精品久久久av久久久 | 永久免费观看美女裸体的网站 | 九九久久精品国产免费看小说 | 无码乱肉视频免费大全合集 | 国产精品久久久久7777 | 国产无av码在线观看 | 久久午夜无码鲁丝片午夜精品 | 成人片黄网站色大片免费观看 | 国产内射爽爽大片视频社区在线 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 51国偷自产一区二区三区 | 国产精品18久久久久久麻辣 | 无码一区二区三区在线观看 | 一本色道久久综合狠狠躁 | 久久无码专区国产精品s | 亚洲精品一区二区三区大桥未久 | 中国女人内谢69xxxx | 牲欲强的熟妇农村老妇女视频 | 2020久久香蕉国产线看观看 | 国产农村妇女高潮大叫 | 成年美女黄网站色大免费全看 | 亚洲小说图区综合在线 | 无码人妻精品一区二区三区下载 | 久久精品国产99精品亚洲 | 老子影院午夜精品无码 | 亚洲日韩中文字幕在线播放 | 国产一区二区三区精品视频 | 久久99精品国产麻豆 | 成人影院yy111111在线观看 | 国产九九九九九九九a片 | 亚洲精品久久久久中文第一幕 | 嫩b人妻精品一区二区三区 | 2020最新国产自产精品 | 久久综合九色综合欧美狠狠 | 国产精品二区一区二区aⅴ污介绍 | 好屌草这里只有精品 | 妺妺窝人体色www在线小说 | 中文字幕乱码人妻无码久久 | 国内揄拍国内精品少妇国语 | 国产人妻精品一区二区三区不卡 | 亚洲精品成人av在线 | 国产成人av免费观看 | 亚洲第一网站男人都懂 | 性欧美疯狂xxxxbbbb | 国产成人人人97超碰超爽8 | 又大又紧又粉嫩18p少妇 | 国产一区二区不卡老阿姨 | 成人无码视频免费播放 | 国产亚洲日韩欧美另类第八页 | 四十如虎的丰满熟妇啪啪 | 麻豆成人精品国产免费 | 精品欧洲av无码一区二区三区 | 日本熟妇人妻xxxxx人hd | 日韩亚洲欧美中文高清在线 | 国产婷婷色一区二区三区在线 | 丰满岳乱妇在线观看中字无码 | 无码精品国产va在线观看dvd | 亚洲色在线无码国产精品不卡 | 帮老师解开蕾丝奶罩吸乳网站 | 中文字幕 人妻熟女 | 国产精品亚洲综合色区韩国 | 国产精品无码永久免费888 | 乱码午夜-极国产极内射 | 天天av天天av天天透 | 国产人妻精品一区二区三区不卡 | 国产一精品一av一免费 | 大肉大捧一进一出好爽视频 | 精品久久8x国产免费观看 | 国产色视频一区二区三区 | 久久亚洲精品中文字幕无男同 | 国产av人人夜夜澡人人爽麻豆 | 亚洲国产欧美国产综合一区 | 桃花色综合影院 | 亚洲精品中文字幕 | 最近的中文字幕在线看视频 | 激情人妻另类人妻伦 | 丰满妇女强制高潮18xxxx | 亚洲精品久久久久久一区二区 | 3d动漫精品啪啪一区二区中 | a在线观看免费网站大全 | 欧美xxxx黑人又粗又长 | 爽爽影院免费观看 | 樱花草在线社区www | 亚洲精品国产a久久久久久 | 激情国产av做激情国产爱 | 人人妻人人澡人人爽精品欧美 | 成人精品视频一区二区三区尤物 | 天天躁夜夜躁狠狠是什么心态 | 色五月五月丁香亚洲综合网 | 日本大香伊一区二区三区 | 久久精品女人的天堂av | 成人精品一区二区三区中文字幕 | 亚洲欧美色中文字幕在线 | 成熟人妻av无码专区 | 午夜无码人妻av大片色欲 | 波多野结衣乳巨码无在线观看 | 国产成人无码av片在线观看不卡 | 性开放的女人aaa片 | 亚洲中文字幕在线观看 | 亚洲精品一区三区三区在线观看 | 久久久久久av无码免费看大片 | 任你躁在线精品免费 | 无人区乱码一区二区三区 | 亚洲国产av美女网站 | 2020久久香蕉国产线看观看 | 国产在线精品一区二区高清不卡 | 又色又爽又黄的美女裸体网站 | 强伦人妻一区二区三区视频18 | 88国产精品欧美一区二区三区 | 日本乱人伦片中文三区 | 国产成人无码区免费内射一片色欲 | 人人妻人人澡人人爽精品欧美 | 中文无码伦av中文字幕 | 娇妻被黑人粗大高潮白浆 | 黑森林福利视频导航 | 国产乱子伦视频在线播放 | 波多野结衣aⅴ在线 | 国产一区二区三区精品视频 | 国产无av码在线观看 | 欧美人与善在线com | 一个人免费观看的www视频 | 乱人伦人妻中文字幕无码久久网 | 亚洲国产精品久久人人爱 | 扒开双腿疯狂进出爽爽爽视频 | 熟女俱乐部五十路六十路av | 欧美精品国产综合久久 | a片在线免费观看 | 国语自产偷拍精品视频偷 | 亚洲色成人中文字幕网站 | 在线 国产 欧美 亚洲 天堂 | 国产成人无码a区在线观看视频app | 永久免费观看美女裸体的网站 | а√天堂www在线天堂小说 | 男女下面进入的视频免费午夜 | 久9re热视频这里只有精品 | 无码国产色欲xxxxx视频 | 国内老熟妇对白xxxxhd | 久久精品99久久香蕉国产色戒 | 兔费看少妇性l交大片免费 | 国产无遮挡又黄又爽又色 | 亚洲精品无码人妻无码 | 久久精品人人做人人综合 | 丝袜 中出 制服 人妻 美腿 | 国产精品嫩草久久久久 | 亚洲日韩av一区二区三区四区 | 国产精品高潮呻吟av久久4虎 | 在线播放亚洲第一字幕 | 300部国产真实乱 | 国产凸凹视频一区二区 | 国产午夜视频在线观看 | 国产又爽又猛又粗的视频a片 | 荫蒂被男人添的好舒服爽免费视频 | 亚洲精品中文字幕乱码 | 日韩精品无码一区二区中文字幕 | 狠狠色色综合网站 | 大屁股大乳丰满人妻 | 日韩精品a片一区二区三区妖精 | 中文久久乱码一区二区 | 97夜夜澡人人爽人人喊中国片 | 中文字幕无码av波多野吉衣 | 欧美高清在线精品一区 | 成人片黄网站色大片免费观看 | 亚洲春色在线视频 | 少妇愉情理伦片bd | 亚洲综合伊人久久大杳蕉 | 久久97精品久久久久久久不卡 | 正在播放老肥熟妇露脸 | 美女扒开屁股让男人桶 | 国产国产精品人在线视 | 国产精品99久久精品爆乳 | 四虎国产精品一区二区 | 亚洲日韩中文字幕在线播放 | 国产真人无遮挡作爱免费视频 | 精品日本一区二区三区在线观看 | 奇米影视7777久久精品人人爽 | 给我免费的视频在线观看 | 波多野结衣一区二区三区av免费 | 青青草原综合久久大伊人精品 | 日本丰满护士爆乳xxxx | 麻豆国产人妻欲求不满 | 欧美老妇与禽交 | 国产午夜无码精品免费看 | 免费国产成人高清在线观看网站 | 色偷偷人人澡人人爽人人模 | 四十如虎的丰满熟妇啪啪 | 一二三四在线观看免费视频 | 亚洲熟妇色xxxxx欧美老妇 | 免费观看黄网站 | 粉嫩少妇内射浓精videos | 亚洲国产成人a精品不卡在线 | 兔费看少妇性l交大片免费 | 无码人妻少妇伦在线电影 | 日韩欧美中文字幕公布 | 少妇的肉体aa片免费 | 九九久久精品国产免费看小说 | 桃花色综合影院 | 亚洲一区二区三区在线观看网站 | 亚洲欧洲日本综合aⅴ在线 | 无码人妻av免费一区二区三区 | 精品一区二区三区波多野结衣 | 国产成人无码区免费内射一片色欲 | 国产激情无码一区二区 | 国产精品高潮呻吟av久久 | 波多野结衣一区二区三区av免费 | 人妻与老人中文字幕 | 风流少妇按摩来高潮 | 亚洲欧美国产精品久久 | 中文字幕无码av激情不卡 | 日本精品久久久久中文字幕 | 国产成人综合在线女婷五月99播放 | 激情国产av做激情国产爱 | 国产做国产爱免费视频 | 久久综合九色综合97网 | 天堂а√在线中文在线 | 亚洲国产欧美日韩精品一区二区三区 | 成人欧美一区二区三区黑人免费 | 欧美日韩视频无码一区二区三 | 伊人色综合久久天天小片 | 欧美一区二区三区 | 午夜精品一区二区三区在线观看 | 超碰97人人射妻 | 国产精品亚洲五月天高清 | 天干天干啦夜天干天2017 | 国产情侣作爱视频免费观看 | 精品亚洲韩国一区二区三区 | 精品国产成人一区二区三区 | 4hu四虎永久在线观看 | 欧美怡红院免费全部视频 | 亚洲精品一区二区三区四区五区 | 超碰97人人射妻 | 天堂亚洲2017在线观看 | 亚洲综合精品香蕉久久网 | 国产精品无码一区二区桃花视频 | 男女爱爱好爽视频免费看 | 欧美人与动性行为视频 | 乱人伦中文视频在线观看 | 欧洲精品码一区二区三区免费看 | 国产婷婷色一区二区三区在线 | 国产另类ts人妖一区二区 | 国产色视频一区二区三区 | 亚洲毛片av日韩av无码 | 麻豆国产人妻欲求不满 | 欧美人与动性行为视频 | 国内综合精品午夜久久资源 | 色欲av亚洲一区无码少妇 | 国产欧美熟妇另类久久久 | 久久久亚洲欧洲日产国码αv | 大胆欧美熟妇xx | 国产手机在线αⅴ片无码观看 | 成 人 免费观看网站 | 国产精品第一国产精品 | 熟女少妇在线视频播放 | 日韩精品无码一区二区中文字幕 | 亚洲日韩精品欧美一区二区 | 亚洲第一无码av无码专区 | 亚洲欧美综合区丁香五月小说 | 欧美成人午夜精品久久久 | aⅴ亚洲 日韩 色 图网站 播放 | 国内精品人妻无码久久久影院 | 99国产精品白浆在线观看免费 | 亚洲色大成网站www | 国产免费久久久久久无码 | 性欧美大战久久久久久久 | 无码国产乱人伦偷精品视频 | 亚洲国产精品一区二区美利坚 | 国产精品99久久精品爆乳 | 麻豆国产97在线 | 欧洲 | 影音先锋中文字幕无码 | 国产午夜精品一区二区三区嫩草 | 天天拍夜夜添久久精品 | 在教室伦流澡到高潮hnp视频 | 国产色xx群视频射精 | 好爽又高潮了毛片免费下载 | 亚洲色欲久久久综合网东京热 | 美女扒开屁股让男人桶 | 少妇人妻偷人精品无码视频 | 久久精品中文闷骚内射 | 一二三四在线观看免费视频 | 一本色道久久综合狠狠躁 | 久久久久成人精品免费播放动漫 | 日本www一道久久久免费榴莲 | 国产婷婷色一区二区三区在线 | 日本大乳高潮视频在线观看 | 亚洲精品成a人在线观看 | 精品亚洲成av人在线观看 | 亚洲区欧美区综合区自拍区 | 又大又黄又粗又爽的免费视频 | 巨爆乳无码视频在线观看 | 精品久久久无码中文字幕 | 少妇性l交大片欧洲热妇乱xxx | 午夜免费福利小电影 | 婷婷五月综合激情中文字幕 | 久久国产36精品色熟妇 | 国产人妻精品午夜福利免费 | 国产内射老熟女aaaa | 国产亚洲欧美日韩亚洲中文色 | 国产偷国产偷精品高清尤物 | 99精品国产综合久久久久五月天 | 一本久道久久综合婷婷五月 | 亚洲精品国产第一综合99久久 | 激情五月综合色婷婷一区二区 | 日韩精品久久久肉伦网站 | 激情内射日本一区二区三区 | 国产成人久久精品流白浆 | 亚洲热妇无码av在线播放 | 日日摸日日碰夜夜爽av | 国产艳妇av在线观看果冻传媒 | 亚洲第一网站男人都懂 | 内射白嫩少妇超碰 | 久久这里只有精品视频9 | 领导边摸边吃奶边做爽在线观看 | 国产成人综合美国十次 | 两性色午夜视频免费播放 | 人妻无码αv中文字幕久久琪琪布 | 免费无码一区二区三区蜜桃大 | 99精品久久毛片a片 | 国产精品人人爽人人做我的可爱 | 国产精品国产自线拍免费软件 | 天天综合网天天综合色 | 麻豆成人精品国产免费 | 久久久婷婷五月亚洲97号色 | 成人影院yy111111在线观看 | 久久久久久久人妻无码中文字幕爆 | 激情国产av做激情国产爱 | 日本在线高清不卡免费播放 | 亚洲精品一区二区三区婷婷月 | 亚洲国产成人av在线观看 | 亚洲精品久久久久中文第一幕 | 性色av无码免费一区二区三区 | 一区二区传媒有限公司 | 国产99久久精品一区二区 | 无套内射视频囯产 | 亚洲经典千人经典日产 | a国产一区二区免费入口 | 中文字幕精品av一区二区五区 | 亚洲熟妇自偷自拍另类 | 丰满岳乱妇在线观看中字无码 | 玩弄中年熟妇正在播放 | 国产精品无码成人午夜电影 | 日日摸夜夜摸狠狠摸婷婷 | 国产免费无码一区二区视频 | 亚洲色在线无码国产精品不卡 | 日本一区二区更新不卡 | 性欧美大战久久久久久久 | 在线观看免费人成视频 | 夜夜躁日日躁狠狠久久av | 99久久精品无码一区二区毛片 | 亚洲国产欧美在线成人 | 人妻中文无码久热丝袜 | 国产香蕉97碰碰久久人人 | 久久久久成人精品免费播放动漫 | 欧美一区二区三区视频在线观看 | 欧美性黑人极品hd | 久久久国产精品无码免费专区 | 亚洲精品成人av在线 | 国产97色在线 | 免 | 两性色午夜免费视频 | 国产激情综合五月久久 | av小次郎收藏 | 人妻夜夜爽天天爽三区 | 国产精品99爱免费视频 | 国产人妻久久精品二区三区老狼 | 久久综合九色综合欧美狠狠 | 亚洲成av人片在线观看无码不卡 | 中文字幕 人妻熟女 | 在线播放亚洲第一字幕 | 人人超人人超碰超国产 | 少妇性l交大片 | 国产精品第一区揄拍无码 | 性史性农村dvd毛片 | 国产无遮挡吃胸膜奶免费看 | 欧美日韩久久久精品a片 | 日本高清一区免费中文视频 | 亚洲另类伦春色综合小说 | 国产一精品一av一免费 | 在线视频网站www色 | 亚洲码国产精品高潮在线 | 成人试看120秒体验区 | 日本丰满熟妇videos | 久久99精品国产.久久久久 | 少妇高潮一区二区三区99 | 激情综合激情五月俺也去 | 在线亚洲高清揄拍自拍一品区 | 亚洲成a人片在线观看无码 | 欧美老熟妇乱xxxxx | 国产一精品一av一免费 | 色噜噜亚洲男人的天堂 | 99久久人妻精品免费一区 | 免费国产黄网站在线观看 | 丰满人妻一区二区三区免费视频 | 亚洲国产欧美国产综合一区 | 亚洲色www成人永久网址 | 国内精品一区二区三区不卡 | 无码人妻出轨黑人中文字幕 | 丝袜美腿亚洲一区二区 | 精品久久久久久人妻无码中文字幕 | 欧美丰满熟妇xxxx | 国产精品高潮呻吟av久久 | 性欧美videos高清精品 | 久久久久成人精品免费播放动漫 | 国产精品内射视频免费 | 无套内射视频囯产 | 久久久国产精品无码免费专区 | 男女猛烈xx00免费视频试看 | 亚洲精品一区二区三区四区五区 | 日本熟妇人妻xxxxx人hd | 我要看www免费看插插视频 | 黑人大群体交免费视频 | 精品熟女少妇av免费观看 | 麻豆md0077饥渴少妇 | 亚洲欧美精品aaaaaa片 | 国产成人精品优优av | 亚洲色偷偷偷综合网 | 一本久久伊人热热精品中文字幕 | 日本护士xxxxhd少妇 | 色婷婷欧美在线播放内射 | 一本久久伊人热热精品中文字幕 | 国产乱人伦偷精品视频 | 亚洲精品久久久久中文第一幕 | www国产亚洲精品久久久日本 | 久久精品国产大片免费观看 | 少妇人妻av毛片在线看 | 国产人成高清在线视频99最全资源 | 伊人久久大香线蕉亚洲 | 又粗又大又硬毛片免费看 | 亚洲欧美日韩综合久久久 | 国产亚洲人成a在线v网站 | 中国女人内谢69xxxxxa片 | 88国产精品欧美一区二区三区 | 精品无码国产自产拍在线观看蜜 | 久久国产精品_国产精品 | 精品无码一区二区三区爱欲 | 久久精品中文闷骚内射 | 久久精品女人的天堂av | а√天堂www在线天堂小说 | 熟妇人妻激情偷爽文 | 性史性农村dvd毛片 | 午夜男女很黄的视频 | 日本一本二本三区免费 | 少妇愉情理伦片bd | 初尝人妻少妇中文字幕 | 国产成人午夜福利在线播放 | 九九综合va免费看 | 免费无码一区二区三区蜜桃大 | 久久午夜无码鲁丝片秋霞 | 日韩欧美群交p片內射中文 | 亚洲中文无码av永久不收费 | 狠狠色丁香久久婷婷综合五月 | 成人亚洲精品久久久久 | 亚洲啪av永久无码精品放毛片 | 日韩av激情在线观看 | а√天堂www在线天堂小说 | 精品无人国产偷自产在线 | 又色又爽又黄的美女裸体网站 | 妺妺窝人体色www在线小说 | 88国产精品欧美一区二区三区 | 国产热a欧美热a在线视频 | 国产精品.xx视频.xxtv | 色欲综合久久中文字幕网 | 亚洲高清偷拍一区二区三区 | 免费看少妇作爱视频 | 无码帝国www无码专区色综合 | 亚洲午夜福利在线观看 | 中文字幕日韩精品一区二区三区 | 久久精品国产精品国产精品污 | 夜夜高潮次次欢爽av女 | 亚洲综合久久一区二区 | 99精品无人区乱码1区2区3区 | 人人妻人人澡人人爽精品欧美 | 野外少妇愉情中文字幕 | 国内精品久久久久久中文字幕 | 国产9 9在线 | 中文 | 成人欧美一区二区三区黑人免费 | 国产人妻久久精品二区三区老狼 | 久久天天躁夜夜躁狠狠 | 成人片黄网站色大片免费观看 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 全黄性性激高免费视频 | 免费观看黄网站 | 麻豆成人精品国产免费 | 无套内谢的新婚少妇国语播放 | 精品人妻人人做人人爽 | 性欧美大战久久久久久久 | 波多野结衣一区二区三区av免费 | 久久无码中文字幕免费影院蜜桃 | 精品日本一区二区三区在线观看 | 大乳丰满人妻中文字幕日本 | 国产精品久久久久影院嫩草 | 国内精品人妻无码久久久影院 | 1000部啪啪未满十八勿入下载 | 精品久久久久久人妻无码中文字幕 | 亚洲天堂2017无码中文 | 国产成人无码午夜视频在线观看 | 99re在线播放 | 国产人妻人伦精品1国产丝袜 | 扒开双腿疯狂进出爽爽爽视频 | 午夜丰满少妇性开放视频 | 国产亚洲精品久久久久久大师 | 麻豆国产丝袜白领秘书在线观看 | √8天堂资源地址中文在线 | 国产精品无码mv在线观看 | 18无码粉嫩小泬无套在线观看 | 少妇人妻大乳在线视频 | 亚洲一区二区三区含羞草 | 欧美性生交活xxxxxdddd | 中文字幕无线码免费人妻 | 久久精品丝袜高跟鞋 | 国产成人无码区免费内射一片色欲 | 日日天日日夜日日摸 | 国产亚洲精品久久久久久国模美 | 超碰97人人做人人爱少妇 | 国产 浪潮av性色四虎 | 亚洲色成人中文字幕网站 | 国产精华av午夜在线观看 | 亚洲精品中文字幕久久久久 | 国产成人人人97超碰超爽8 | 久久久久久久人妻无码中文字幕爆 | 麻豆人妻少妇精品无码专区 | 国产色视频一区二区三区 | 国产精品久久国产精品99 | 最新国产麻豆aⅴ精品无码 | 全黄性性激高免费视频 | 国产精品久久久久久无码 | 97久久精品无码一区二区 | 大肉大捧一进一出视频出来呀 | 欧美xxxx黑人又粗又长 | 任你躁在线精品免费 | 亚洲欧洲日本综合aⅴ在线 | 无码午夜成人1000部免费视频 | 暴力强奷在线播放无码 | 强开小婷嫩苞又嫩又紧视频 | 人妻夜夜爽天天爽三区 | 国产精品对白交换视频 | 国产成人精品久久亚洲高清不卡 | 亚洲日韩av一区二区三区中文 | 熟妇人妻无乱码中文字幕 | 内射巨臀欧美在线视频 | 欧美激情综合亚洲一二区 | 国产精品久久久午夜夜伦鲁鲁 | 7777奇米四色成人眼影 | 亚洲精品久久久久久久久久久 | 无码一区二区三区在线观看 | 国产在线一区二区三区四区五区 | 国产精品亚洲专区无码不卡 | 亚洲午夜久久久影院 | 久久久亚洲欧洲日产国码αv | 天堂а√在线地址中文在线 | 精品国产麻豆免费人成网站 | 草草网站影院白丝内射 | 成熟人妻av无码专区 | 亚洲日本va中文字幕 | 亚洲国产精品一区二区美利坚 | 亚洲 a v无 码免 费 成 人 a v | 亚洲精品一区二区三区在线观看 | 97久久超碰中文字幕 | 久久精品中文闷骚内射 | 自拍偷自拍亚洲精品10p | 超碰97人人射妻 | 99精品视频在线观看免费 | 噜噜噜亚洲色成人网站 | 亚洲高清偷拍一区二区三区 | 国内精品人妻无码久久久影院蜜桃 | 亚洲乱码中文字幕在线 | 色一情一乱一伦一区二区三欧美 | 噜噜噜亚洲色成人网站 | 青青久在线视频免费观看 | 99re在线播放 | 精品偷拍一区二区三区在线看 | 国产成人无码区免费内射一片色欲 | 国内精品久久久久久中文字幕 | av人摸人人人澡人人超碰下载 | 亚洲一区二区三区国产精华液 | 99国产精品白浆在线观看免费 | 蜜臀av在线播放 久久综合激激的五月天 | 福利一区二区三区视频在线观看 | 久久人人爽人人爽人人片av高清 | 国产精品亚洲а∨无码播放麻豆 | 亚洲综合色区中文字幕 | 欧美亚洲国产一区二区三区 | 暴力强奷在线播放无码 | 狂野欧美性猛xxxx乱大交 | 成 人影片 免费观看 | yw尤物av无码国产在线观看 | 88国产精品欧美一区二区三区 | 少妇无套内谢久久久久 | 国产绳艺sm调教室论坛 | 嫩b人妻精品一区二区三区 | 51国偷自产一区二区三区 | 成人欧美一区二区三区 | 97精品国产97久久久久久免费 | 亚洲精品鲁一鲁一区二区三区 | 国产亚av手机在线观看 | 无码午夜成人1000部免费视频 | 欧美性猛交xxxx富婆 | 又大又黄又粗又爽的免费视频 | 国产亚洲精品久久久久久久 | 久久综合香蕉国产蜜臀av | 一本久道久久综合婷婷五月 | 97人妻精品一区二区三区 | 日韩在线不卡免费视频一区 | 欧美一区二区三区 | 天下第一社区视频www日本 | 日韩人妻少妇一区二区三区 | 久久99精品国产麻豆蜜芽 | www成人国产高清内射 | 日本精品高清一区二区 | 中文字幕无码av波多野吉衣 | 国产精品视频免费播放 | 蜜桃视频插满18在线观看 | 欧美性生交活xxxxxdddd | 自拍偷自拍亚洲精品10p | 波多野结衣av一区二区全免费观看 | 亚洲精品国偷拍自产在线麻豆 | 97资源共享在线视频 | 福利一区二区三区视频在线观看 | 欧美日韩综合一区二区三区 | 99riav国产精品视频 | 免费无码的av片在线观看 | 在线看片无码永久免费视频 | 国产精品久久久久久亚洲毛片 | 精品人妻人人做人人爽 | 日本欧美一区二区三区乱码 | 国产色精品久久人妻 | 亚洲第一网站男人都懂 | 国产精品美女久久久网av | 激情内射亚州一区二区三区爱妻 | 性欧美熟妇videofreesex | 国产亚洲精品久久久久久大师 | 久久亚洲精品成人无码 | 精品国产福利一区二区 | 99国产欧美久久久精品 | 中文无码精品a∨在线观看不卡 | 国产人妻精品午夜福利免费 | 亚洲 日韩 欧美 成人 在线观看 | 欧美喷潮久久久xxxxx | 在线观看免费人成视频 | 老司机亚洲精品影院 | 国内少妇偷人精品视频免费 | 精品一区二区不卡无码av | 免费无码一区二区三区蜜桃大 | 巨爆乳无码视频在线观看 | 国产精品高潮呻吟av久久 | 国产精品无码久久av | 国产人妻精品一区二区三区 | 捆绑白丝粉色jk震动捧喷白浆 | 亚洲一区二区三区在线观看网站 | 国产精品igao视频网 | 伊人久久大香线蕉av一区二区 | 特大黑人娇小亚洲女 | 成 人 免费观看网站 | 亚洲成av人片天堂网无码】 | 在线播放亚洲第一字幕 | 东京热无码av男人的天堂 | 图片小说视频一区二区 | 国产农村乱对白刺激视频 | 少妇厨房愉情理9仑片视频 | а√资源新版在线天堂 | 日本成熟视频免费视频 | 四虎永久在线精品免费网址 | 中国女人内谢69xxxx | 亚洲va欧美va天堂v国产综合 | 成人无码视频免费播放 | 日本丰满熟妇videos | 欧美老熟妇乱xxxxx | 国内精品人妻无码久久久影院 | 波多野42部无码喷潮在线 | 亚洲精品国产第一综合99久久 | 少妇的肉体aa片免费 | 欧美zoozzooz性欧美 | 18禁止看的免费污网站 | 国产精品久久久久久久影院 | 亚洲综合精品香蕉久久网 | 无码人妻丰满熟妇区五十路百度 | 亚洲gv猛男gv无码男同 | 国产精品亚洲一区二区三区喷水 | 蜜桃臀无码内射一区二区三区 | 强伦人妻一区二区三区视频18 | 狠狠亚洲超碰狼人久久 | 亚洲日韩乱码中文无码蜜桃臀网站 | 久久久久久久人妻无码中文字幕爆 | 粉嫩少妇内射浓精videos | 永久黄网站色视频免费直播 | 久精品国产欧美亚洲色aⅴ大片 | 高中生自慰www网站 | 18禁止看的免费污网站 | 日韩 欧美 动漫 国产 制服 | 亚洲 另类 在线 欧美 制服 | 人妻人人添人妻人人爱 | a国产一区二区免费入口 | 日韩精品无码一区二区中文字幕 | 色一情一乱一伦 | 一本色道久久综合狠狠躁 | 欧美日韩一区二区免费视频 | 永久黄网站色视频免费直播 | 国内综合精品午夜久久资源 | 蜜臀av在线播放 久久综合激激的五月天 | 岛国片人妻三上悠亚 | 97无码免费人妻超级碰碰夜夜 | 成人精品视频一区二区三区尤物 | 人人超人人超碰超国产 | 国产xxx69麻豆国语对白 | 国产在热线精品视频 | 国产凸凹视频一区二区 | 国产成人亚洲综合无码 | а√天堂www在线天堂小说 | 麻豆果冻传媒2021精品传媒一区下载 | 图片区 小说区 区 亚洲五月 | 性生交大片免费看l | 中文字幕+乱码+中文字幕一区 | 无套内谢的新婚少妇国语播放 | 亚洲va中文字幕无码久久不卡 | 亚洲乱码日产精品bd | 久久久久久久久888 | 亚洲欧美国产精品专区久久 | 亚洲精品www久久久 | 无码免费一区二区三区 | 小鲜肉自慰网站xnxx | a国产一区二区免费入口 | 欧美日韩一区二区免费视频 | 51国偷自产一区二区三区 | 久久精品国产日本波多野结衣 | 中文字幕乱妇无码av在线 | 亚洲精品国产第一综合99久久 | 狠狠色欧美亚洲狠狠色www | 成 人 网 站国产免费观看 | 欧美熟妇另类久久久久久不卡 | 美女黄网站人色视频免费国产 | 欧洲欧美人成视频在线 | 国产免费观看黄av片 | 成人欧美一区二区三区黑人 | 波多野结衣av一区二区全免费观看 | 亚洲国产精品久久人人爱 | 性色欲网站人妻丰满中文久久不卡 | 免费人成在线视频无码 | 久久99精品久久久久久 | 日本一区二区三区免费高清 | 免费看少妇作爱视频 | 精品国精品国产自在久国产87 | √天堂中文官网8在线 | 大屁股大乳丰满人妻 | 国产一区二区三区精品视频 | 国产成人无码av片在线观看不卡 | 搡女人真爽免费视频大全 | 精品无码一区二区三区爱欲 | 在线观看欧美一区二区三区 | 欧洲熟妇色 欧美 | 欧美国产日产一区二区 | 激情国产av做激情国产爱 | 秋霞特色aa大片 | 欧美国产日韩亚洲中文 | 亚拍精品一区二区三区探花 | 日韩 欧美 动漫 国产 制服 | 免费观看激色视频网站 | 无码av最新清无码专区吞精 | 在线播放无码字幕亚洲 | 色欲综合久久中文字幕网 | 人人澡人人妻人人爽人人蜜桃 | 男人的天堂av网站 | 国产真实夫妇视频 | 亚洲国产成人av在线观看 | 午夜男女很黄的视频 | 无码帝国www无码专区色综合 | 中文字幕av无码一区二区三区电影 | 欧美日韩一区二区免费视频 | 成人无码视频在线观看网站 | 国产手机在线αⅴ片无码观看 | 欧美高清在线精品一区 | 7777奇米四色成人眼影 | 国产人妻精品一区二区三区不卡 | 亚洲人交乣女bbw | 国产人妻久久精品二区三区老狼 | 国产精品无码一区二区三区不卡 | 国内精品久久久久久中文字幕 | www国产精品内射老师 | 国产精品手机免费 | 成在人线av无码免观看麻豆 | 特级做a爰片毛片免费69 | 国产9 9在线 | 中文 | 亚洲呦女专区 | 激情国产av做激情国产爱 | 九九久久精品国产免费看小说 | 国产av一区二区三区最新精品 | 国产精品久久久久影院嫩草 | 少妇人妻大乳在线视频 | 在线欧美精品一区二区三区 | 亚洲成av人片天堂网无码】 | 久久久久久av无码免费看大片 | 国产成人无码a区在线观看视频app | 中文字幕无码日韩欧毛 | 国产麻豆精品一区二区三区v视界 | 无码免费一区二区三区 | 少妇无码吹潮 | 亚洲精品国产精品乱码视色 | 国产精品人妻一区二区三区四 | 日韩av无码一区二区三区 | 亚洲国产一区二区三区在线观看 | 荫蒂被男人添的好舒服爽免费视频 | 色婷婷香蕉在线一区二区 | 波多野结衣一区二区三区av免费 | 正在播放东北夫妻内射 | 无码人妻出轨黑人中文字幕 | 天天摸天天碰天天添 | 欧美大屁股xxxxhd黑色 | 欧美变态另类xxxx | www一区二区www免费 | 最近的中文字幕在线看视频 | 国产成人无码区免费内射一片色欲 | 国产精品无码久久av | 久久综合久久自在自线精品自 | 丰满人妻一区二区三区免费视频 | 国产成人综合美国十次 | 国产无遮挡吃胸膜奶免费看 | www一区二区www免费 | 欧美性猛交xxxx富婆 | 乱人伦人妻中文字幕无码 | 亚洲成a人片在线观看日本 | 天海翼激烈高潮到腰振不止 | 天天爽夜夜爽夜夜爽 | 国产97色在线 | 免 | 久久久久久av无码免费看大片 | 极品尤物被啪到呻吟喷水 | 中文字幕无码免费久久99 | 巨爆乳无码视频在线观看 | 国产精品手机免费 | 岛国片人妻三上悠亚 | 亚洲成av人在线观看网址 | 久久精品99久久香蕉国产色戒 | 久久国产精品_国产精品 | 一二三四在线观看免费视频 | 亚洲国产成人a精品不卡在线 | 成人免费视频在线观看 | 国产精品怡红院永久免费 | а√天堂www在线天堂小说 | 亚洲精品无码人妻无码 | 中文字幕无线码免费人妻 | 久久久久久久久蜜桃 | 男人和女人高潮免费网站 | 久久久久免费精品国产 | 国产亚洲精品久久久久久久久动漫 | 97精品人妻一区二区三区香蕉 | 在线播放免费人成毛片乱码 | 日本精品少妇一区二区三区 | 捆绑白丝粉色jk震动捧喷白浆 | 最新版天堂资源中文官网 | 无码播放一区二区三区 | 色婷婷香蕉在线一区二区 | 蜜臀aⅴ国产精品久久久国产老师 | 又大又紧又粉嫩18p少妇 | 欧美成人免费全部网站 | 中文无码精品a∨在线观看不卡 | 国产亚洲精品久久久久久大师 | 300部国产真实乱 | 国产无遮挡吃胸膜奶免费看 | 亚洲中文字幕av在天堂 | 国产黄在线观看免费观看不卡 | 国产精品亚洲一区二区三区喷水 | 亚洲日韩一区二区三区 | 狂野欧美性猛交免费视频 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲成av人片天堂网无码】 | 国产成人精品一区二区在线小狼 | 一本久久伊人热热精品中文字幕 | 给我免费的视频在线观看 | 国产精品多人p群无码 | 国产农村妇女高潮大叫 | 亚欧洲精品在线视频免费观看 | 亚洲国产高清在线观看视频 | 99er热精品视频 | 亚洲成av人影院在线观看 | 人妻体内射精一区二区三四 | 日日麻批免费40分钟无码 | 国产人妻精品一区二区三区不卡 | 国产精品久久久av久久久 | 日日摸天天摸爽爽狠狠97 | 中文字幕无码av激情不卡 | 成人免费视频一区二区 | 久久久久99精品国产片 | 国产女主播喷水视频在线观看 | 国产精品久久久久影院嫩草 | 东京热男人av天堂 | 亚洲成a人片在线观看无码 | 精品无码一区二区三区的天堂 | 欧美国产日韩亚洲中文 | 亚洲一区二区三区四区 | 亚洲爆乳无码专区 | 97久久超碰中文字幕 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 久久久av男人的天堂 | 天堂а√在线中文在线 | 亚洲国产精品美女久久久久 | 巨爆乳无码视频在线观看 | 九一九色国产 | 丰满妇女强制高潮18xxxx | 天天摸天天碰天天添 | 好爽又高潮了毛片免费下载 | 1000部夫妻午夜免费 | 18无码粉嫩小泬无套在线观看 | 日本一卡2卡3卡四卡精品网站 | 亚洲中文字幕无码中文字在线 | 美女极度色诱视频国产 | 无遮挡国产高潮视频免费观看 | 国产一区二区三区精品视频 | 激情爆乳一区二区三区 | 欧美乱妇无乱码大黄a片 | 高潮毛片无遮挡高清免费视频 | 国产成人一区二区三区别 | 国产精品久免费的黄网站 | 久久精品国产一区二区三区 | 精品国产麻豆免费人成网站 | 国产无遮挡又黄又爽又色 | 国产成人精品一区二区在线小狼 | 久久国产36精品色熟妇 | 国产一区二区三区四区五区加勒比 | 久久精品中文字幕大胸 | 丰满人妻被黑人猛烈进入 | 国产亚洲精品精品国产亚洲综合 | 亚洲色www成人永久网址 | 成人女人看片免费视频放人 | 97精品国产97久久久久久免费 | 久久精品人人做人人综合试看 | 亚洲成av人综合在线观看 | 亚洲色成人中文字幕网站 | 国产在线精品一区二区高清不卡 | 国产 精品 自在自线 | 中文字幕乱码中文乱码51精品 | 欧美性猛交xxxx富婆 | 熟妇女人妻丰满少妇中文字幕 | 国产香蕉97碰碰久久人人 | 精品aⅴ一区二区三区 | 免费无码一区二区三区蜜桃大 | 日本成熟视频免费视频 | 精品国产精品久久一区免费式 | 性色欲情网站iwww九文堂 | av无码不卡在线观看免费 | 十八禁真人啪啪免费网站 | 欧美黑人巨大xxxxx | 亚洲精品久久久久avwww潮水 | 色窝窝无码一区二区三区色欲 | 精品成人av一区二区三区 | 无码国产乱人伦偷精品视频 | 在线成人www免费观看视频 | 久久亚洲日韩精品一区二区三区 | 欧美三级不卡在线观看 | 精品一区二区三区波多野结衣 | 精品人妻av区 | 日日躁夜夜躁狠狠躁 | 久久亚洲国产成人精品性色 | 国产精品第一区揄拍无码 | 老司机亚洲精品影院 | 午夜熟女插插xx免费视频 | 精品久久久久香蕉网 | 一本大道久久东京热无码av | 色婷婷香蕉在线一区二区 | 免费网站看v片在线18禁无码 | 夫妻免费无码v看片 | 99久久久国产精品无码免费 | 四虎永久在线精品免费网址 | 97久久超碰中文字幕 | 18无码粉嫩小泬无套在线观看 | 中文字幕色婷婷在线视频 | 色婷婷久久一区二区三区麻豆 | 精品偷自拍另类在线观看 | 精品少妇爆乳无码av无码专区 | 亚洲另类伦春色综合小说 | 国产偷国产偷精品高清尤物 | 丰满岳乱妇在线观看中字无码 | 伊人久久婷婷五月综合97色 | 日韩成人一区二区三区在线观看 | 国内精品一区二区三区不卡 | 亚洲欧美精品aaaaaa片 | 成 人 网 站国产免费观看 | 久久久中文字幕日本无吗 | 精品无码国产一区二区三区av | 色五月丁香五月综合五月 | 日韩亚洲欧美中文高清在线 | 欧美日韩精品 | 久久精品成人欧美大片 | 欧美乱妇无乱码大黄a片 | 波多野结衣一区二区三区av免费 | 人妻少妇被猛烈进入中文字幕 | 小sao货水好多真紧h无码视频 | 成人无码精品一区二区三区 | 精品亚洲韩国一区二区三区 | 亚洲爆乳无码专区 | 巨爆乳无码视频在线观看 | 麻豆国产人妻欲求不满 | 狂野欧美性猛xxxx乱大交 | 奇米影视7777久久精品 | 久久综合久久自在自线精品自 | 中文字幕人成乱码熟女app | 丰满少妇人妻久久久久久 | 强开小婷嫩苞又嫩又紧视频 | 国产av一区二区三区最新精品 | 国产明星裸体无码xxxx视频 | 夜精品a片一区二区三区无码白浆 | 熟妇女人妻丰满少妇中文字幕 | 欧美成人午夜精品久久久 | 国产欧美亚洲精品a | 九九综合va免费看 | 亚洲中文字幕在线观看 | 国内丰满熟女出轨videos | 欧美阿v高清资源不卡在线播放 | 黑人巨大精品欧美黑寡妇 | 色综合久久中文娱乐网 | 大肉大捧一进一出视频出来呀 | 亚洲综合色区中文字幕 | 曰本女人与公拘交酡免费视频 | 300部国产真实乱 | 国内揄拍国内精品人妻 | 综合激情五月综合激情五月激情1 | 强奷人妻日本中文字幕 | 激情亚洲一区国产精品 | 色综合久久88色综合天天 | 乱人伦人妻中文字幕无码 | 丰腴饱满的极品熟妇 | 久久综合久久自在自线精品自 | 一二三四在线观看免费视频 | 中文毛片无遮挡高清免费 | 国产精品二区一区二区aⅴ污介绍 | 少女韩国电视剧在线观看完整 | 在线精品国产一区二区三区 | 日韩av无码一区二区三区 | 日本一区二区三区免费高清 | 久久久久se色偷偷亚洲精品av | 成人无码精品一区二区三区 | 日韩精品乱码av一区二区 | 亚洲国产精品无码久久久久高潮 | 97色伦图片97综合影院 | 2019nv天堂香蕉在线观看 | 天天综合网天天综合色 | 98国产精品综合一区二区三区 | 亚洲日韩av一区二区三区中文 | 人妻无码αv中文字幕久久琪琪布 | 美女黄网站人色视频免费国产 | 国产av一区二区三区最新精品 | 精品国产一区二区三区av 性色 | 亚洲中文字幕久久无码 | 好男人www社区 | 麻豆果冻传媒2021精品传媒一区下载 | 99久久精品午夜一区二区 | 国语自产偷拍精品视频偷 | 亚洲日本va午夜在线电影 | v一区无码内射国产 | 少妇人妻偷人精品无码视频 | 日韩人妻无码一区二区三区久久99 | 国产乱人伦av在线无码 | 色诱久久久久综合网ywww | 98国产精品综合一区二区三区 | 无码精品国产va在线观看dvd | 熟女俱乐部五十路六十路av | 久久久久久久人妻无码中文字幕爆 | 久久久久亚洲精品中文字幕 | 亚洲va中文字幕无码久久不卡 | 中国女人内谢69xxxxxa片 | 国产精品久久久 | 女人高潮内射99精品 | 国产va免费精品观看 | 午夜成人1000部免费视频 | a在线观看免费网站大全 | 狠狠色丁香久久婷婷综合五月 | 国产精品成人av在线观看 | 亚洲欧美日韩国产精品一区二区 | 中文字幕无码日韩专区 | 成熟人妻av无码专区 | 久久精品中文字幕一区 | 极品尤物被啪到呻吟喷水 | 久久久久亚洲精品中文字幕 | 老头边吃奶边弄进去呻吟 | 丰满少妇弄高潮了www | 精品厕所偷拍各类美女tp嘘嘘 | 亚洲熟妇色xxxxx欧美老妇y | 无码人妻黑人中文字幕 | 亲嘴扒胸摸屁股激烈网站 | 亚洲大尺度无码无码专区 | 久久精品女人天堂av免费观看 | 亚洲男人av天堂午夜在 | 亚洲国产日韩a在线播放 | 国产精品怡红院永久免费 | 色综合天天综合狠狠爱 | 永久黄网站色视频免费直播 | 国产97色在线 | 免 | 欧洲熟妇色 欧美 | 99久久婷婷国产综合精品青草免费 | 97精品国产97久久久久久免费 | 在线亚洲高清揄拍自拍一品区 | 狂野欧美激情性xxxx | 亚洲国产精品无码一区二区三区 | 久久人人爽人人人人片 | 亚洲综合久久一区二区 | 秋霞特色aa大片 | 亚洲男人av香蕉爽爽爽爽 | 欧美野外疯狂做受xxxx高潮 | 国产美女极度色诱视频www | 亚洲欧美国产精品专区久久 | 国色天香社区在线视频 | 久久久亚洲欧洲日产国码αv | 色综合久久久久综合一本到桃花网 | 日本熟妇浓毛 | 丝袜 中出 制服 人妻 美腿 | 内射后入在线观看一区 | 久久久精品456亚洲影院 | 国产精品美女久久久久av爽李琼 | 熟女少妇在线视频播放 | 内射老妇bbwx0c0ck | 在教室伦流澡到高潮hnp视频 | 色 综合 欧美 亚洲 国产 | 无码人妻丰满熟妇区毛片18 | 十八禁真人啪啪免费网站 | 亚洲国产欧美日韩精品一区二区三区 | 丝袜足控一区二区三区 | 无码人妻黑人中文字幕 | 亚洲精品美女久久久久久久 | 国产精品久久久av久久久 | 国产精品亚洲专区无码不卡 | 全球成人中文在线 | 亚洲日韩av一区二区三区中文 | 欧美野外疯狂做受xxxx高潮 | 中文字幕亚洲情99在线 | 黄网在线观看免费网站 | 白嫩日本少妇做爰 | 亚洲va欧美va天堂v国产综合 | 亚洲欧美色中文字幕在线 | 成人片黄网站色大片免费观看 | 九九久久精品国产免费看小说 | 亚洲成av人影院在线观看 | 国产成人综合色在线观看网站 | 欧美成人家庭影院 | 少妇被黑人到高潮喷出白浆 | 亚洲色无码一区二区三区 | 国产av人人夜夜澡人人爽麻豆 | 国产精品美女久久久久av爽李琼 | 偷窥日本少妇撒尿chinese | 欧美放荡的少妇 | 大乳丰满人妻中文字幕日本 | 樱花草在线播放免费中文 | 一本久道久久综合狠狠爱 | 黑人大群体交免费视频 | 午夜无码区在线观看 | 精品国产青草久久久久福利 | 精品一二三区久久aaa片 | 少妇愉情理伦片bd | 亚洲精品成人福利网站 | 性欧美大战久久久久久久 | 国色天香社区在线视频 | 熟妇激情内射com | 国产真实乱对白精彩久久 | 亚洲综合伊人久久大杳蕉 | 人人妻人人藻人人爽欧美一区 | 男人和女人高潮免费网站 | 4hu四虎永久在线观看 | 久久精品人妻少妇一区二区三区 | 亚洲国产成人av在线观看 | 婷婷丁香六月激情综合啪 | 久久精品女人的天堂av | 欧美怡红院免费全部视频 | 青春草在线视频免费观看 | 国内揄拍国内精品人妻 | 99久久精品无码一区二区毛片 | 欧美丰满熟妇xxxx性ppx人交 | 欧美怡红院免费全部视频 | 国产精品.xx视频.xxtv | 人人妻人人澡人人爽人人精品浪潮 | 青草青草久热国产精品 | 黑人粗大猛烈进出高潮视频 | 免费看男女做好爽好硬视频 | 久久97精品久久久久久久不卡 | 亚洲自偷精品视频自拍 | 樱花草在线社区www | 国产高清av在线播放 | 丁香花在线影院观看在线播放 | 久久国产精品萌白酱免费 | 一本无码人妻在中文字幕免费 | 成人免费无码大片a毛片 | 一区二区三区高清视频一 | 国产内射爽爽大片视频社区在线 | 国产乡下妇女做爰 | 色一情一乱一伦一视频免费看 | 人妻有码中文字幕在线 | 欧美国产日韩久久mv | 国产精品人妻一区二区三区四 | 国产美女极度色诱视频www | 亚洲色欲色欲天天天www | 久久久精品人妻久久影视 | 亚洲成熟女人毛毛耸耸多 | 天堂а√在线地址中文在线 | 国产在线精品一区二区高清不卡 | 久久无码人妻影院 | 久久亚洲日韩精品一区二区三区 | 四虎永久在线精品免费网址 | 亚洲大尺度无码无码专区 | 日韩无码专区 | 少妇邻居内射在线 | 国产偷自视频区视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 丰满岳乱妇在线观看中字无码 | 国内综合精品午夜久久资源 | 乌克兰少妇性做爰 | 成人试看120秒体验区 | 国产乱码精品一品二品 | 又色又爽又黄的美女裸体网站 | 国产美女精品一区二区三区 | 性欧美牲交xxxxx视频 | 日日干夜夜干 | 成人一区二区免费视频 | 国产精品99爱免费视频 | 久久久精品456亚洲影院 | 老头边吃奶边弄进去呻吟 | 国产黄在线观看免费观看不卡 | 丰满诱人的人妻3 | 中文字幕人妻无码一夲道 | 日本高清一区免费中文视频 | 日本肉体xxxx裸交 | 日韩精品久久久肉伦网站 | 欧美丰满熟妇xxxx性ppx人交 | 国产精品久久久久9999小说 | 成人免费视频视频在线观看 免费 | 中文字幕人妻无码一夲道 | 欧美变态另类xxxx | 国产乱人伦偷精品视频 | 熟女少妇人妻中文字幕 | 色综合久久久无码网中文 | 中文字幕乱码人妻无码久久 | 爆乳一区二区三区无码 | 丰满少妇熟乱xxxxx视频 | 熟妇激情内射com | 日韩av激情在线观看 | 国产亚洲精品久久久ai换 | 国产精品成人av在线观看 | 国产亚洲精品久久久久久大师 | 精品国产青草久久久久福利 | 欧美放荡的少妇 | 在教室伦流澡到高潮hnp视频 | 国产特级毛片aaaaaaa高清 | 国产香蕉尹人综合在线观看 | 沈阳熟女露脸对白视频 | 欧洲欧美人成视频在线 | 精品无人区无码乱码毛片国产 | 成年美女黄网站色大免费全看 | 99精品视频在线观看免费 | 成年美女黄网站色大免费视频 | 无码乱肉视频免费大全合集 | 久久久精品成人免费观看 | 综合人妻久久一区二区精品 | 久久99精品久久久久婷婷 | 久久久国产精品无码免费专区 | 中文字幕乱码中文乱码51精品 |