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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

java 23种设计模式及具体例子 收藏有时间慢慢看

發布時間:2024/4/14 asp.net 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 23种设计模式及具体例子 收藏有时间慢慢看 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代 碼可靠性。 毫無疑問,設計模式于己于他人于系統都是多贏的,設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石一樣。項目中合理的運用 設計模式可以完美的解決很多問題,每種模式在現在中都有相應的原理來與之對應,每一個模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的核心解決 方案,這也是它能被廣泛應用的原因。

一、設計模式的分類

總體來說設計模式分為三大類:

創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。

結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

其實還有兩類:并發型模式和線程池模式。用一個圖片來整體描述一下:

二、Java的23中設計模式

從這一塊開始,我們詳細介紹Java中23種設計模式的概念,應用場景等情況,并結合他們的特點及設計模式的原則進行分析。

1、工廠方法模式(Factory Method)

工廠方法模式分為三種:

11、普通工廠模式,就是建立一個工廠類,對實現了同一接口的一些類進行實例的創建。首先看下關系圖:

舉例如下:(我們舉一個發送郵件和短信的例子)

首先,創建二者的共同接口:

  • public?interface?Sender?{??
  • ????public?void?Send();??
  • }??
  • 其次,創建實現類:

  • public?class?MailSender?implements?Sender?{??
  • ????@Override??
  • ????public?void?Send()?{??
  • ????????System.out.println(“this?is?mailsender!”);??
  • ????}??
  • }??
  • public?class?SmsSender?implements?Sender?{??
  • ??
  • ????@Override??
  • ????public?void?Send()?{??
  • ????????System.out.println(“this?is?sms?sender!”);??
  • ????}??
  • }??
  • 最后,建工廠類:

  • public?class?SendFactory?{??
  • ??
  • ????public?Sender?produce(String?type)?{??
  • ????????if?(“mail”.equals(type))?{??
  • ????????????return?new?MailSender();??
  • ????????}?else?if?(“sms”.equals(type))?{??
  • ????????????return?new?SmsSender();??
  • ????????}?else?{??
  • ????????????System.out.println(“請輸入正確的類型!”);??
  • ????????????return?null;??
  • ????????}??
  • ????}??
  • }??
  • 我們來測試下:

  • public?class?FactoryTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????SendFactory?factory?=?new?SendFactory();??
  • ????????Sender?sender?=?factory.produce(“sms”);??
  • ????????sender.Send();??
  • ????}??
  • }??
  • 輸出:this is sms sender!

    22、多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創建對象,而多個工廠方法模式是提供多個工廠方法,分別創建對象。關系圖:

    ::__IHACKLOG_REMOTE_IMAGE_AUTODOWN_BLOCK__::2

    將上面的代碼做下修改,改動下SendFactory類就行,如下:

    public?class?SendFactory?{ ? public?Sender?produceMail(){ ?
  • ????????return?new?MailSender();??
  • ????}??
  • ??????
  • ????public?Sender?produceSms(){??
  • ????????return?new?SmsSender();??
  • ????}??
  • }??
  • 測試類如下:

  • public?class?FactoryTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????SendFactory?factory?=?new?SendFactory();??
  • ????????Sender?sender?=?factory.produceMail();??
  • ????????sender.Send();??
  • ????}??
  • }??
  • 輸出:this is mailsender!

    33、靜態工廠方法模式,將上面的多個工廠方法模式里的方法置為靜態的,不需要創建實例,直接調用即可。

  • public?class?SendFactory?{??
  • ??????
  • ????public?static?Sender?produceMail(){??
  • ????????return?new?MailSender();??
  • ????}??
  • ??????
  • ????public?static?Sender?produceSms(){??
  • ????????return?new?SmsSender();??
  • ????}??
  • }??
  • public?class?FactoryTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??????
  • ????????Sender?sender?=?SendFactory.produceMail();??
  • ????????sender.Send();??
  • ????}??
  • }??
  • 輸出:this is mailsender!

    總體來說,工廠模式適合:凡是出現了大量的產品需要創建,并且具有共同的接口時,可以通過工廠方法模式進行創建。在以上的三種模式中,第一種如果傳 入的字符串有誤,不能正確創建對象,第三種相對于第二種,不需要實例化工廠類,所以,大多數情況下,我們會選用第三種——靜態工廠方法模式。

    2、抽象工廠模式(Abstract Factory)

    工廠方法模式有一個問題就是,類的創建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮, 有一定的問題,如何解決?就用到抽象工廠模式,創建多個工廠類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼。因為抽象 工廠不太好理解,我們先看看圖,然后就和代碼,就比較容易理解。

    請看例子:

  • public?interface?Sender?{??
  • ????public?void?Send();??
  • }??
  • 兩個實現類:

  • public?class?MailSender?implements?Sender?{??
  • ????@Override??
  • ????public?void?Send()?{??
  • ????????System.out.println(“this?is?mailsender!”);??
  • ????}??
  • }??
  • public?class?SmsSender?implements?Sender?{??
  • ??
  • ????@Override??
  • ????public?void?Send()?{??
  • ????????System.out.println(“this?is?sms?sender!”);??
  • ????}??
  • }??
  • 兩個工廠類:

  • public?class?SendMailFactory?implements?Provider?{??
  • ??????
  • ????@Override??
  • ????public?Sender?produce(){??
  • ????????return?new?MailSender();??
  • ????}??
  • }??
  • public?class?SendSmsFactory?implements?Provider{??
  • ??
  • ????@Override??
  • ????public?Sender?produce()?{??
  • ????????return?new?SmsSender();??
  • ????}??
  • }??
  • 在提供一個接口:

  • public?interface?Provider?{??
  • ????public?Sender?produce();??
  • }??
  • 測試類:

  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Provider?provider?=?new?SendMailFactory();??
  • ????????Sender?sender?=?provider.produce();??
  • ????????sender.Send();??
  • ????}??
  • }??
  • 其實這個模式的好處就是,如果你現在想增加一個功能:發及時信息,則只需做一個實現類,實現Sender接口,同時做一個工廠類,實現Provider接口,就OK了,無需去改動現成的代碼。這樣做,拓展性較好!

    3、單例模式(Singleton

    單例對象(Singleton)是一種常用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:

    1、某些類創建比較頻繁,對于一些大型的對象,這是一筆很大的系統開銷。

    2、省去了new操作符,降低了系統內存的使用頻率,減輕GC壓力。

    3、有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以創建多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式,才能保證核心交易服務器獨立控制整個流程。

    首先我們寫一個簡單的單例類:

  • public?class?Singleton?{??
  • ??
  • ????/*?持有私有靜態實例,防止被引用,此處賦值為null,目的是實現延遲加載?*/??
  • ????private?static?Singleton?instance?=?null;??
  • ??
  • ????/*?私有構造方法,防止被實例化?*/??
  • ????private?Singleton()?{??
  • ????}??
  • ??
  • ????/*?靜態工程方法,創建實例?*/??
  • ????public?static?Singleton?getInstance()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????instance?=?new?Singleton();??
  • ????????}??
  • ????????return?instance;??
  • ????}??
  • ??
  • ????/*?如果該對象被用于序列化,可以保證對象在序列化前后保持一致?*/??
  • ????public?Object?readResolve()?{??
  • ????????return?instance;??
  • ????}??
  • }??
  • 這個類可以滿足基本要求,但是,像這樣毫無線程安全保護的類,如果我們把它放入多線程的環境下,肯定就會出現問題了,如何解決?我們首先會想到對getInstance方法加synchronized關鍵字,如下:

  • public?static?synchronized?Singleton?getInstance()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????instance?=?new?Singleton();??
  • ????????}??
  • ????????return?instance;??
  • ????}??
  • 但是,synchronized關鍵字鎖住的是這個對象,這樣的用法,在性能上會有所下降,因為每次調用getInstance(),都要對對象上鎖,事實上,只有在第一次創建對象的時候需要加鎖,之后就不需要了,所以,這個地方需要改進。我們改成下面這個:

  • public?static?Singleton?getInstance()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????synchronized?(instance)?{??
  • ????????????????if?(instance?==?null)?{??
  • ????????????????????instance?=?new?Singleton();??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????return?instance;??
  • ????}??
  • 似乎解決了之前提到的問題,將synchronized關鍵字加在了內部,也就是說當調用的時候是不需要加鎖的,只有在instance為 null,并創建對象的時候才需要加鎖,性能有一定的提升。但是,這樣的情況,還是有可能有問題的,看下面的情況:在Java指令中創建對象和賦值操作是 分開進行的,也就是說instance = new Singleton();語句是分兩步執行的。但是JVM并不保證這兩個操作的先后順序,也就是說有可能JVM會為新的Singleton實例分配空間, 然后直接賦值給instance成員,然后再去初始化這個Singleton實例。這樣就可能出錯了,我們以A、B兩個線程為例:

    a>A、B線程同時進入了第一個if判斷

    b>A首先進入synchronized塊,由于instance為null,所以它執行instance = new Singleton();

    c>由于JVM內部的優化機制,JVM先畫出了一些分配給Singleton實例的空白內存,并賦值給instance成員(注意此時JVM沒有開始初始化這個實例),然后A離開了synchronized塊。

    d>B進入synchronized塊,由于instance此時不是null,因此它馬上離開了synchronized塊并將結果返回給調用該方法的程序。

    e>此時B線程打算使用Singleton實例,卻發現它沒有被初始化,于是錯誤發生了。

    所以程序還是有可能發生錯誤,其實程序在運行過程是很復雜的,從這點我們就可以看出,尤其是在寫多線程環境下的程序更有難度,有挑戰性。我們對該程序做進一步優化:

  • private?static?class?SingletonFactory{???????????
  • ????????private?static?Singleton?instance?=?new?Singleton();???????????
  • ????}???????????
  • ????public?static?Singleton?getInstance(){???????????
  • ????????return?SingletonFactory.instance;???????????
  • ????}???
  • 實際情況是,單例模式使用內部類來維護單例的實現,JVM內部的機制能夠保證當一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當我們第一 次調用getInstance的時候,JVM能夠幫我們保證instance只被創建一次,并且會保證把賦值給instance的內存初始化完畢,這樣我 們就不用擔心上面的問題。同時該方法也只會在第一次調用的時候使用互斥機制,這樣就解決了低性能問題。這樣我們暫時總結一個完美的單例模式:

  • public?class?Singleton?{??
  • ??
  • ????/*?私有構造方法,防止被實例化?*/??
  • ????private?Singleton()?{??
  • ????}??
  • ??
  • ????/*?此處使用一個內部類來維護單例?*/??
  • ????private?static?class?SingletonFactory?{??
  • ????????private?static?Singleton?instance?=?new?Singleton();??
  • ????}??
  • ??
  • ????/*?獲取實例?*/??
  • ????public?static?Singleton?getInstance()?{??
  • ????????return?SingletonFactory.instance;??
  • ????}??
  • ??
  • ????/*?如果該對象被用于序列化,可以保證對象在序列化前后保持一致?*/??
  • ????public?Object?readResolve()?{??
  • ????????return?getInstance();??
  • ????}??
  • }??
  • 其實說它完美,也不一定,如果在構造函數中拋出異常,實例將永遠得不到創建,也會出錯。所以說,十分完美的東西是沒有的,我們只能根據實際情況,選 擇最適合自己應用場景的實現方法。也有人這樣實現:因為我們只需要在創建類的時候進行同步,所以只要將創建和getInstance()分開,單獨為創建 加synchronized關鍵字,也是可以的:

  • public?class?SingletonTest?{??
  • ??
  • ????private?static?SingletonTest?instance?=?null;??
  • ??
  • ????private?SingletonTest()?{??
  • ????}??
  • ??
  • ????private?static?synchronized?void?syncInit()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????instance?=?new?SingletonTest();??
  • ????????}??
  • ????}??
  • ??
  • ????public?static?SingletonTest?getInstance()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????syncInit();??
  • ????????}??
  • ????????return?instance;??
  • ????}??
  • }??
  • 考慮性能的話,整個程序只需創建一次實例,所以性能也不會有什么影響。

    補充:采用”影子實例”的辦法為單例對象的屬性同步更新

  • public?class?SingletonTest?{??
  • ??
  • ????private?static?SingletonTest?instance?=?null;??
  • ????private?Vector?properties?=?null;??
  • ??
  • ????public?Vector?getProperties()?{??
  • ????????return?properties;??
  • ????}??
  • ??
  • ????private?SingletonTest()?{??
  • ????}??
  • ??
  • ????private?static?synchronized?void?syncInit()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????instance?=?new?SingletonTest();??
  • ????????}??
  • ????}??
  • ??
  • ????public?static?SingletonTest?getInstance()?{??
  • ????????if?(instance?==?null)?{??
  • ????????????syncInit();??
  • ????????}??
  • ????????return?instance;??
  • ????}??
  • ??
  • ????public?void?updateProperties()?{??
  • ????????SingletonTest?shadow?=?new?SingletonTest();??
  • ????????properties?=?shadow.getProperties();??
  • ????}??
  • }??
  • 通過單例模式的學習告訴我們:

    1、單例模式理解起來簡單,但是具體實現起來還是有一定的難度。

    2、synchronized關鍵字鎖定的是對象,在用的時候,一定要在恰當的地方使用(注意需要使用鎖的對象和過程,可能有的時候并不是整個對象及整個過程都需要鎖)。

    到這兒,單例模式基本已經講完了,結尾處,筆者突然想到另一個問題,就是采用類的靜態方法,實現單例模式的效果,也是可行的,此處二者有什么不同?

    首先,靜態類不能實現接口。(從類的角度說是可以的,但是那樣就破壞了靜態了。因為接口中不允許有static修飾的方法,所以即使實現了也是非靜態的)

    其次,單例可以被延遲初始化,靜態類一般在第一次加載是初始化。之所以延遲加載,是因為有些類比較龐大,所以延遲加載有助于提升性能。

    再次,單例類可以被繼承,他的方法可以被覆寫。但是靜態類內部方法都是static,無法被覆寫。

    最后一點,單例類比較靈活,畢竟從實現上只是一個普通的Java類,只要滿足單例的基本需求,你可以在里面隨心所欲的實現一些其它功能,但是靜態類 不行。從上面這些概括中,基本可以看出二者的區別,但是,從另一方面講,我們上面最后實現的那個單例模式,內部就是用一個靜態類來實現的,所以,二者有很 大的關聯,只是我們考慮問題的層面不同罷了。兩種思想的結合,才能造就出完美的解決方案,就像HashMap采用數組+鏈表來實現一樣,其實生活中很多事 情都是這樣,單用不同的方法來處理問題,總是有優點也有缺點,最完美的方法是,結合各個方法的優點,才能最好的解決問題!

    4、建造者模式(Builder)

    工廠類模式提供的是創建單個類的模式,而建造者模式則是將各種產品集中起來進行管理,用來創建復合對象,所謂復合對象就是指某個類具有不同的屬性,其實建造者模式就是前面抽象工廠模式和最后的Test結合起來得到的。我們看一下代碼:

    還和前面一樣,一個Sender接口,兩個實現類MailSender和SmsSender。最后,建造者類如下:

  • public?class?Builder?{??
  • ??????
  • ????private?List<Sender>?list?=?new?ArrayList<Sender>();??
  • ??????
  • ????public?void?produceMailSender(int?count){??
  • ????????for(int?i=0;?i<count;?i++){??
  • ????????????list.add(new?MailSender());??
  • ????????}??
  • ????}??
  • ??????
  • ????public?void?produceSmsSender(int?count){??
  • ????????for(int?i=0;?i<count;?i++){??
  • ????????????list.add(new?SmsSender());??
  • ????????}??
  • ????}??
  • }??
  • 測試類:

  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Builder?builder?=?new?Builder();??
  • ????????builder.produceMailSender(10);??
  • ????}??
  • }??
  • 從這點看出,建造者模式將很多功能集成到一個類里,這個類可以創造出比較復雜的東西。所以與工程模式的區別就是:工廠模式關注的是創建單個產品,而建造者模式則關注創建符合對象,多個部分。因此,是選擇工廠模式還是建造者模式,依實際情況而定。

    5、原型模式(Prototype)

    原型模式雖然是創建型的模式,但是與工程模式沒有關系,從名字即可看出,該模式的思想就是將一個對象作為原型,對其進行復制、克隆,產生一個和原對象類似的新對象。本小結會通過對象的復制,進行講解。在Java中,復制對象是通過clone()實現的,先創建一個原型類:

  • public?class?Prototype?implements?Cloneable?{??
  • ??
  • ????public?Object?clone()?throws?CloneNotSupportedException?{??
  • ????????Prototype?proto?=?(Prototype)?super.clone();??
  • ????????return?proto;??
  • ????}??
  • }??
  • 很簡單,一個原型類,只需要實現Cloneable接口,覆寫clone方法,此處clone方法可以改成任意的名稱,因為Cloneable接口 是個空接口,你可以任意定義實現類的方法名,如cloneA或者cloneB,因為此處的重點是super.clone()這句 話,super.clone()調用的是Object的clone()方法,而在Object類中,clone()是native的,具體怎么實現,我會 在另一篇文章中,關于解讀Java中本地方法的調用,此處不再深究。在這兒,我將結合對象的淺復制和深復制來說一下,首先需要了解對象深、淺復制的概念:

    淺復制:將一個對象復制后,基本數據類型的變量都會重新創建,而引用類型,指向的還是原對象所指向的。

    深復制:將一個對象復制后,不論是基本數據類型還有引用類型,都是重新創建的。簡單來說,就是深復制進行了完全徹底的復制,而淺復制不徹底。

    此處,寫一個深淺復制的例子:

  • public?class?Prototype?implements?Cloneable,?Serializable?{??
  • ??
  • ????private?static?final?long?serialVersionUID?=?1L;??
  • ????private?String?string;??
  • ??
  • ????private?SerializableObject?obj;??
  • ??
  • ????/*?淺復制?*/??
  • ????public?Object?clone()?throws?CloneNotSupportedException?{??
  • ????????Prototype?proto?=?(Prototype)?super.clone();??
  • ????????return?proto;??
  • ????}??
  • ??
  • ????/*?深復制?*/??
  • ????public?Object?deepClone()?throws?IOException,?ClassNotFoundException?{??
  • ??
  • ????????/*?寫入當前對象的二進制流?*/??
  • ????????ByteArrayOutputStream?bos?=?new?ByteArrayOutputStream();??
  • ????????ObjectOutputStream?oos?=?new?ObjectOutputStream(bos);??
  • ????????oos.writeObject(this);??
  • ??
  • ????????/*?讀出二進制流產生的新對象?*/??
  • ????????ByteArrayInputStream?bis?=?new?ByteArrayInputStream(bos.toByteArray());??
  • ????????ObjectInputStream?ois?=?new?ObjectInputStream(bis);??
  • ????????return?ois.readObject();??
  • ????}??
  • ??
  • ????public?String?getString()?{??
  • ????????return?string;??
  • ????}??
  • ??
  • ????public?void?setString(String?string)?{??
  • ????????this.string?=?string;??
  • ????}??
  • ??
  • ????public?SerializableObject?getObj()?{??
  • ????????return?obj;??
  • ????}??
  • ??
  • ????public?void?setObj(SerializableObject?obj)?{??
  • ????????this.obj?=?obj;??
  • ????}??
  • ??
  • }??
  • ??
  • class?SerializableObject?implements?Serializable?{??
  • ????private?static?final?long?serialVersionUID?=?1L;??
  • }??
  • 要實現深復制,需要采用流的形式讀入當前對象的二進制輸入,再寫出二進制數據對應的對象。

    7種結構型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

    ?適配器模式將某個類的接口轉換成客戶端期望的另一個接口表示,目的是消除由于接口不匹配所造成的類的兼容性問題。主要分為三類:類的適配器模式、對象的適配器模式、接口的適配器模式。首先,我們來看看類的適配器模式,先看類圖:

    核心思想就是:有一個Source類,擁有一個方法,待適配,目標接口時Targetable,通過Adapter類,將Source的功能擴展到Targetable里,看代碼:

  • public?class?Source?{??
  • ??
  • ????public?void?method1()?{??
  • ????????System.out.println(“this?is?original?method!”);??
  • ????}??
  • }??
  • public?interface?Targetable?{??
  • ??
  • ????/*?與原類中的方法相同?*/??
  • ????public?void?method1();??
  • ??
  • ????/*?新類的方法?*/??
  • ????public?void?method2();??
  • }??
  • public?class?Adapter?extends?Source?implements?Targetable?{??
  • ??
  • ????@Override??
  • ????public?void?method2()?{??
  • ????????System.out.println(“this?is?the?targetable?method!”);??
  • ????}??
  • }??
  • Adapter類繼承Source類,實現Targetable接口,下面是測試類:

  • public?class?AdapterTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Targetable?target?=?new?Adapter();??
  • ????????target.method1();??
  • ????????target.method2();??
  • ????}??
  • }??
  • 輸出:

    this is original method! this is the targetable method!

    這樣Targetable接口的實現類就具有了Source類的功能。

    對象的適配器模式

    基本思路和類的適配器模式相同,只是將Adapter類作修改,這次不繼承Source類,而是持有Source類的實例,以達到解決兼容性的問題。看圖:

    只需要修改Adapter類的源碼即可:

  • public?class?Wrapper?implements?Targetable?{??
  • ??
  • ????private?Source?source;??
  • ??????
  • ????public?Wrapper(Source?source){??
  • ????????super();??
  • ????????this.source?=?source;??
  • ????}??
  • ????@Override??
  • ????public?void?method2()?{??
  • ????????System.out.println(“this?is?the?targetable?method!”);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?method1()?{??
  • ????????source.method1();??
  • ????}??
  • }??
  • 測試類:

  • public?class?AdapterTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Source?source?=?new?Source();??
  • ????????Targetable?target?=?new?Wrapper(source);??
  • ????????target.method1();??
  • ????????target.method2();??
  • ????}??
  • }??
  • 輸出與第一種一樣,只是適配的方法不同而已。

    第三種適配器模式是接口的適配器模式,接口的適配器是這樣的:有時我們寫的一個接口 中有多個抽象方法,當我們寫該接口的實現類時,必須實現該接口的所有方法,這明顯有時比較浪費,因為并不是所有的方法都是我們需要的,有時只需要某一些, 此處為了解決這個問題,我們引入了接口的適配器模式,借助于一個抽象類,該抽象類實現了該接口,實現了所有的方法,而我們不和原始的接口打交道,只和該抽 象類取得聯系,所以我們寫一個類,繼承該抽象類,重寫我們需要的方法就行。看一下類圖:

    這個很好理解,在實際開發中,我們也常會遇到這種接口中定義了太多的方法,以致于有時我們在一些實現類中并不是都需要。看代碼:

  • public?interface?Sourceable?{??
  • ??????
  • ????public?void?method1();??
  • ????public?void?method2();??
  • }??
  • 抽象類Wrapper2:

  • public?abstract?class?Wrapper2?implements?Sourceable{??
  • ??????
  • ????public?void?method1(){}??
  • ????public?void?method2(){}??
  • }??
  • public?class?SourceSub1?extends?Wrapper2?{??
  • ????public?void?method1(){??
  • ????????System.out.println(“the?sourceable?interface’s?first?Sub1!”);??
  • ????}??
  • }??
  • public?class?SourceSub2?extends?Wrapper2?{??
  • ????public?void?method2(){??
  • ????????System.out.println(“the?sourceable?interface’s?second?Sub2!”);??
  • ????}??
  • }??
  • public?class?WrapperTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Sourceable?source1?=?new?SourceSub1();??
  • ????????Sourceable?source2?=?new?SourceSub2();??
  • ??????????
  • ????????source1.method1();??
  • ????????source1.method2();??
  • ????????source2.method1();??
  • ????????source2.method2();??
  • ????}??
  • }??
  • 測試輸出:

    the sourceable interface’s first Sub1! the sourceable interface’s second Sub2!

    達到了我們的效果!

    ?講了這么多,總結一下三種適配器模式的應用場景:

    類的適配器模式:當希望將一個類轉換成滿足另一個新接口的類時,可以使用類的適配器模式,創建一個新類,繼承原有的類,實現新的接口即可。

    對象的適配器模式:當希望將一個對象轉換成滿足另一個新接口的對象時,可以創建一個Wrapper類,持有原類的一個實例,在Wrapper類的方法中,調用實例的方法就行。

    接口的適配器模式:當不希望實現一個接口中所有的方法時,可以創建一個抽象類Wrapper,實現所有方法,我們寫別的類的時候,繼承抽象類即可。

    7、裝飾模式(Decorator)

    顧名思義,裝飾模式就是給一個對象增加一些新的功能,而且是動態的,要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例,關系圖如下:

    Source類是被裝飾類,Decorator類是一個裝飾類,可以為Source類動態的添加一些功能,代碼如下:

  • public?interface?Sourceable?{??
  • ????public?void?method();??
  • }??
  • public?class?Source?implements?Sourceable?{??
  • ??
  • ????@Override??
  • ????public?void?method()?{??
  • ????????System.out.println(“the?original?method!”);??
  • ????}??
  • }??
  • public?class?Decorator?implements?Sourceable?{??
  • ??
  • ????private?Sourceable?source;??
  • ??????
  • ????public?Decorator(Sourceable?source){??
  • ????????super();??
  • ????????this.source?=?source;??
  • ????}??
  • ????@Override??
  • ????public?void?method()?{??
  • ????????System.out.println(“before?decorator!”);??
  • ????????source.method();??
  • ????????System.out.println(“after?decorator!”);??
  • ????}??
  • }??
  • 測試類:

  • public?class?DecoratorTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Sourceable?source?=?new?Source();??
  • ????????Sourceable?obj?=?new?Decorator(source);??
  • ????????obj.method();??
  • ????}??
  • }??
  • 輸出:

    before decorator! the original method! after decorator!

    裝飾器模式的應用場景:

    1、需要擴展一個類的功能。

    2、動態的為一個對象增加功能,而且還能動態撤銷。(繼承不能做到這一點,繼承的功能是靜態的,不能動態增刪。)

    缺點:產生過多相似的對象,不易排錯!

    8、代理模式(Proxy)

    其實每個模式名稱就表明了該模式的作用,代理模式就是多一個代理類出來,替原對象進行一些操作,比如我們在租房子的時候回去找中介,為什么呢?因為 你對該地區房屋的信息掌握的不夠全面,希望找一個更熟悉的人去幫你做,此處的代理就是這個意思。再如我們有的時候打官司,我們需要請律師,因為律師在法律 方面有專長,可以替我們進行操作,表達我們的想法。先來看看關系圖:

    根據上文的闡述,代理模式就比較容易的理解了,我們看下代碼:

  • public?interface?Sourceable?{??
  • ????public?void?method();??
  • }??
  • public?class?Source?implements?Sourceable?{??
  • ??
  • ????@Override??
  • ????public?void?method()?{??
  • ????????System.out.println(“the?original?method!”);??
  • ????}??
  • }??
  • public?class?Proxy?implements?Sourceable?{??
  • ??
  • ????private?Source?source;??
  • ????public?Proxy(){??
  • ????????super();??
  • ????????this.source?=?new?Source();??
  • ????}??
  • ????@Override??
  • ????public?void?method()?{??
  • ????????before();??
  • ????????source.method();??
  • ????????atfer();??
  • ????}??
  • ????private?void?atfer()?{??
  • ????????System.out.println(“after?proxy!”);??
  • ????}??
  • ????private?void?before()?{??
  • ????????System.out.println(“before?proxy!”);??
  • ????}??
  • }??
  • 測試類:

  • public?class?ProxyTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Sourceable?source?=?new?Proxy();??
  • ????????source.method();??
  • ????}??
  • ??
  • }??
  • 輸出:

    before proxy! the original method! after proxy!

    代理模式的應用場景:

    如果已有的方法在使用的時候需要對原有的方法進行改進,此時有兩種辦法:

    1、修改原有的方法來適應。這樣違反了“對擴展開放,對修改關閉”的原則。

    2、就是采用一個代理類調用原有的方法,且對產生的結果進行控制。這種方法就是代理模式。

    使用代理模式,可以將功能劃分的更加清晰,有助于后期維護!

    9、外觀模式(Facade)

    外觀模式是為了解決類與類之家的依賴關系的,像spring一樣,可以將類和類之間的關系配置到配置文件中,而外觀模式就是將他們的關系放在一個Facade類中,降低了類類之間的耦合度,該模式中沒有涉及到接口,看下類圖:(我們以一個計算機的啟動過程為例)

    我們先看下實現類:

  • public?class?CPU?{??
  • ??????
  • ????public?void?startup(){??
  • ????????System.out.println(“cpu?startup!”);??
  • ????}??
  • ??????
  • ????public?void?shutdown(){??
  • ????????System.out.println(“cpu?shutdown!”);??
  • ????}??
  • }??
  • public?class?Memory?{??
  • ??????
  • ????public?void?startup(){??
  • ????????System.out.println(“memory?startup!”);??
  • ????}??
  • ??????
  • ????public?void?shutdown(){??
  • ????????System.out.println(“memory?shutdown!”);??
  • ????}??
  • }??
  • public?class?Disk?{??
  • ??????
  • ????public?void?startup(){??
  • ????????System.out.println(“disk?startup!”);??
  • ????}??
  • ??????
  • ????public?void?shutdown(){??
  • ????????System.out.println(“disk?shutdown!”);??
  • ????}??
  • }??
  • public?class?Computer?{??
  • ????private?CPU?cpu;??
  • ????private?Memory?memory;??
  • ????private?Disk?disk;??
  • ??????
  • ????public?Computer(){??
  • ????????cpu?=?new?CPU();??
  • ????????memory?=?new?Memory();??
  • ????????disk?=?new?Disk();??
  • ????}??
  • ??????
  • ????public?void?startup(){??
  • ????????System.out.println(“start?the?computer!”);??
  • ????????cpu.startup();??
  • ????????memory.startup();??
  • ????????disk.startup();??
  • ????????System.out.println(“start?computer?finished!”);??
  • ????}??
  • ??????
  • ????public?void?shutdown(){??
  • ????????System.out.println(“begin?to?close?the?computer!”);??
  • ????????cpu.shutdown();??
  • ????????memory.shutdown();??
  • ????????disk.shutdown();??
  • ????????System.out.println(“computer?closed!”);??
  • ????}??
  • }??
  • User類如下:

  • public?class?User?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Computer?computer?=?new?Computer();??
  • ????????computer.startup();??
  • ????????computer.shutdown();??
  • ????}??
  • }??
  • 輸出:

    start the computer! cpu startup! memory startup! disk startup! start computer finished! begin to close the computer! cpu shutdown! memory shutdown! disk shutdown! computer closed!

    如果我們沒有Computer類,那么,CPU、Memory、Disk他們之間將會相互持有實例,產生關系,這樣會造成嚴重的依賴,修改一個類, 可能會帶來其他類的修改,這不是我們想要看到的,有了Computer類,他們之間的關系被放在了Computer類里,這樣就起到了解耦的作用,這,就 是外觀模式!

    10、橋接模式(Bridge)

    橋接模式就是把事物和其具體實現分開,使他們可以各自獨立的變化。橋接的用意是:將抽象化與實現化解耦,使得二者可以獨立變化, 像我們常用的JDBC橋DriverManager一樣,JDBC進行連接數據庫的時候,在各個數據庫之間進行切換,基本不需要動太多的代碼,甚至絲毫不 用動,原因就是JDBC提供統一接口,每個數據庫提供各自的實現,用一個叫做數據庫驅動的程序來橋接就行了。我們來看看關系圖:

    實現代碼:

    先定義接口:

  • public?interface?Sourceable?{??
  • ????public?void?method();??
  • }??
  • 分別定義兩個實現類:

  • public?class?SourceSub1?implements?Sourceable?{??
  • ??
  • ????@Override??
  • ????public?void?method()?{??
  • ????????System.out.println(“this?is?the?first?sub!”);??
  • ????}??
  • }??
  • public?class?SourceSub2?implements?Sourceable?{??
  • ??
  • ????@Override??
  • ????public?void?method()?{??
  • ????????System.out.println(“this?is?the?second?sub!”);??
  • ????}??
  • }??
  • 定義一個橋,持有Sourceable的一個實例:

  • public?abstract?class?Bridge?{??
  • ????private?Sourceable?source;??
  • ??
  • ????public?void?method(){??
  • ????????source.method();??
  • ????}??
  • ??????
  • ????public?Sourceable?getSource()?{??
  • ????????return?source;??
  • ????}??
  • ??
  • ????public?void?setSource(Sourceable?source)?{??
  • ????????this.source?=?source;??
  • ????}??
  • }??
  • public?class?MyBridge?extends?Bridge?{??
  • ????public?void?method(){??
  • ????????getSource().method();??
  • ????}??
  • }??
  • 測試類:

  • public?class?BridgeTest?{??
  • ??????
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????Bridge?bridge?=?new?MyBridge();??
  • ??????????
  • ????????/*調用第一個對象*/??
  • ????????Sourceable?source1?=?new?SourceSub1();??
  • ????????bridge.setSource(source1);??
  • ????????bridge.method();??
  • ??????????
  • ????????/*調用第二個對象*/??
  • ????????Sourceable?source2?=?new?SourceSub2();??
  • ????????bridge.setSource(source2);??
  • ????????bridge.method();??
  • ????}??
  • }??
  • output:

    this is the first sub! this is the second sub!

    這樣,就通過對Bridge類的調用,實現了對接口Sourceable的實現類SourceSub1和SourceSub2的調用。接下來我再畫個圖,大家就應該明白了,因為這個圖是我們JDBC連接的原理,有數據庫學習基礎的,一結合就都懂了。

    2

    11、組合模式(Composite)

    組合模式有時又叫部分-整體模式在處理類似樹形結構的問題時比較方便,看看關系圖:

    直接來看代碼:

  • public?class?TreeNode?{??
  • ??????
  • ????private?String?name;??
  • ????private?TreeNode?parent;??
  • ????private?Vector<TreeNode>?children?=?new?Vector<TreeNode>();??
  • ??????
  • ????public?TreeNode(String?name){??
  • ????????this.name?=?name;??
  • ????}??
  • ??
  • ????public?String?getName()?{??
  • ????????return?name;??
  • ????}??
  • ??
  • ????public?void?setName(String?name)?{??
  • ????????this.name?=?name;??
  • ????}??
  • ??
  • ????public?TreeNode?getParent()?{??
  • ????????return?parent;??
  • ????}??
  • ??
  • ????public?void?setParent(TreeNode?parent)?{??
  • ????????this.parent?=?parent;??
  • ????}??
  • ??????
  • ????//添加孩子節點??
  • ????public?void?add(TreeNode?node){??
  • ????????children.add(node);??
  • ????}??
  • ??????
  • ????//刪除孩子節點??
  • ????public?void?remove(TreeNode?node){??
  • ????????children.remove(node);??
  • ????}??
  • ??????
  • ????//取得孩子節點??
  • ????public?Enumeration<TreeNode>?getChildren(){??
  • ????????return?children.elements();??
  • ????}??
  • }??
  • public?class?Tree?{??
  • ??
  • ????TreeNode?root?=?null;??
  • ??
  • ????public?Tree(String?name)?{??
  • ????????root?=?new?TreeNode(name);??
  • ????}??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Tree?tree?=?new?Tree(“A”);??
  • ????????TreeNode?nodeB?=?new?TreeNode(“B”);??
  • ????????TreeNode?nodeC?=?new?TreeNode(“C”);??
  • ??????????
  • ????????nodeB.add(nodeC);??
  • ????????tree.root.add(nodeB);??
  • ????????System.out.println(“build?the?tree?finished!”);??
  • ????}??
  • }??
  • 使用場景:將多個對象組合在一起進行操作,常用于表示樹形結構中,例如二叉樹,數等。

    12、享元模式(Flyweight)

    享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候可以減少內存的開銷,通常與工廠模式一起使用。

    FlyWeightFactory負責創建和管理享元單元,當一個客戶端請求時,工廠需要檢查當前對象池中是否有符合條件的對象,如果有,就返回已 經存在的對象,如果沒有,則創建一個新對象,FlyWeight是超類。一提到共享池,我們很容易聯想到Java里面的JDBC連接池,想想每個連接的特 點,我們不難總結出:適用于作共享的一些個對象,他們有一些共有的屬性,就拿數據庫連接池來說,url、driverClassName、 username、password及dbname,這些屬性對于每個連接來說都是一樣的,所以就適合用享元模式來處理,建一個工廠類,將上述類似屬性作 為內部數據,其它的作為外部數據,在方法調用時,當做參數傳進來,這樣就節省了空間,減少了實例的數量。

    看個例子:

    看下數據庫連接池的代碼:

  • public?class?ConnectionPool?{??
  • ??????
  • ????private?Vector<Connection>?pool;??
  • ??????
  • ????/*公有屬性*/??
  • ????private?String?url?=?“jdbc:mysql://localhost:3306/test”;??
  • ????private?String?username?=?“root”;??
  • ????private?String?password?=?“root”;??
  • ????private?String?driverClassName?=?“com.mysql.jdbc.Driver”;??
  • ??
  • ????private?int?poolSize?=?100;??
  • ????private?static?ConnectionPool?instance?=?null;??
  • ????Connection?conn?=?null;??
  • ??
  • ????/*構造方法,做一些初始化工作*/??
  • ????private?ConnectionPool()?{??
  • ????????pool?=?new?Vector<Connection>(poolSize);??
  • ??
  • ????????for?(int?i?=?0;?i?<?poolSize;?i++)?{??
  • ????????????try?{??
  • ????????????????Class.forName(driverClassName);??
  • ????????????????conn?=?DriverManager.getConnection(url,?username,?password);??
  • ????????????????pool.add(conn);??
  • ????????????}?catch?(ClassNotFoundException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}?catch?(SQLException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????/*?返回連接到連接池?*/??
  • ????public?synchronized?void?release()?{??
  • ????????pool.add(conn);??
  • ????}??
  • ??
  • ????/*?返回連接池中的一個數據庫連接?*/??
  • ????public?synchronized?Connection?getConnection()?{??
  • ????????if?(pool.size()?>?0)?{??
  • ????????????Connection?conn?=?pool.get(0);??
  • ????????????pool.remove(conn);??
  • ????????????return?conn;??
  • ????????}?else?{??
  • ????????????return?null;??
  • ????????}??
  • ????}??
  • }??
  • 通過連接池的管理,實現了數據庫連接的共享,不需要每一次都重新創建連接,節省了數據庫重新創建的開銷,提升了系統的性能!本章講解了7種結構型模式,因為篇幅的問題,剩下的11種行為型模式,

    本章是關于設計模式的最后一講,會講到第三種設計模式——行為型模式,共11種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命 令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。這段時間一直在寫關于設計模式的東西,終于寫到一半了,寫博文是個很費時間的東西, 因為我得為讀者負責,不論是圖還是代碼還是表述,都希望能盡量寫清楚,以便讀者理解,我想不論是我還是讀者,都希望看到高質量的博文出來,從我本人出發, 我會一直堅持下去,不斷更新,源源動力來自于讀者朋友們的不斷支持,我會盡自己的努力,寫好每一篇文章!希望大家能不斷給出意見和建議,共同打造完美的博 文!

    先來張圖,看看這11中模式的關系:

    第一類:通過父類與子類的關系進行實現。第二類:兩個類之間。第三類:類的狀態。第四類:通過中間類

    13、策略模式(strategy)

    策略模式定義了一系列算法,并將每個算法封裝起來,使他們可以相互替換,且算法的變化不會影響到使用算法的客戶。需要設計一個接口,為一系列實現類提供統一的方法,多個實現類實現該接口,設計一個抽象類(可有可無,屬于輔助類),提供輔助函數,關系圖如下:

    圖中ICalculator提供同意的方法, AbstractCalculator是輔助類,提供輔助方法,接下來,依次實現下每個類:

    首先統一接口:

  • public?interface?ICalculator?{??
  • ????public?int?calculate(String?exp);??
  • }??
  • 輔助類:

  • public?abstract?class?AbstractCalculator?{??
  • ??????
  • ????public?int[]?split(String?exp,String?opt){??
  • ????????String?array[]?=?exp.split(opt);??
  • ????????int?arrayInt[]?=?new?int[2];??
  • ????????arrayInt[0]?=?Integer.parseInt(array[0]);??
  • ????????arrayInt[1]?=?Integer.parseInt(array[1]);??
  • ????????return?arrayInt;??
  • ????}??
  • }??
  • 三個實現類:

  • public?class?Plus?extends?AbstractCalculator?implements?ICalculator?{??
  • ??
  • ????@Override??
  • ????public?int?calculate(String?exp)?{??
  • ????????int?arrayInt[]?=?split(exp,”\\+”);??
  • ????????return?arrayInt[0]+arrayInt[1];??
  • ????}??
  • }??
  • public?class?Minus?extends?AbstractCalculator?implements?ICalculator?{??
  • ??
  • ????@Override??
  • ????public?int?calculate(String?exp)?{??
  • ????????int?arrayInt[]?=?split(exp,”-“);??
  • ????????return?arrayInt[0]-arrayInt[1];??
  • ????}??
  • ??
  • }??
  • public?class?Multiply?extends?AbstractCalculator?implements?ICalculator?{??
  • ??
  • ????@Override??
  • ????public?int?calculate(String?exp)?{??
  • ????????int?arrayInt[]?=?split(exp,”\\*”);??
  • ????????return?arrayInt[0]*arrayInt[1];??
  • ????}??
  • }??
  • 簡單的測試類:

  • public?class?StrategyTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????String?exp?=?“2+8″;??
  • ????????ICalculator?cal?=?new?Plus();??
  • ????????int?result?=?cal.calculate(exp);??
  • ????????System.out.println(result);??
  • ????}??
  • }??
  • 輸出:10

    策略模式的決定權在用戶,系統本身提供不同算法的實現,新增或者刪除算法,對各種算法做封裝。因此,策略模式多用在算法決策系統中,外部用戶只需要決定用哪個算法即可。

    14、模板方法模式(Template Method)

    解釋一下模板方法模式,就是指:一個抽象類中,有一個主方法,再定義1…n個方法,可以是抽象的,也可以是實際的方法,定義一個類,繼承該抽象類,重寫抽象方法,通過調用抽象類,實現對子類的調用,先看個關系圖:

    就是在AbstractCalculator類中定義一個主方法calculate,calculate()調用spilt()等,Plus和 Minus分別繼承AbstractCalculator類,通過對AbstractCalculator的調用實現對子類的調用,看下面的例子:

  • public?abstract?class?AbstractCalculator?{??
  • ??????
  • ????/*主方法,實現對本類其它方法的調用*/??
  • ????public?final?int?calculate(String?exp,String?opt){??
  • ????????int?array[]?=?split(exp,opt);??
  • ????????return?calculate(array[0],array[1]);??
  • ????}??
  • ??????
  • ????/*被子類重寫的方法*/??
  • ????abstract?public?int?calculate(int?num1,int?num2);??
  • ??????
  • ????public?int[]?split(String?exp,String?opt){??
  • ????????String?array[]?=?exp.split(opt);??
  • ????????int?arrayInt[]?=?new?int[2];??
  • ????????arrayInt[0]?=?Integer.parseInt(array[0]);??
  • ????????arrayInt[1]?=?Integer.parseInt(array[1]);??
  • ????????return?arrayInt;??
  • ????}??
  • }??
  • public?class?Plus?extends?AbstractCalculator?{??
  • ??
  • ????@Override??
  • ????public?int?calculate(int?num1,int?num2)?{??
  • ????????return?num1?+?num2;??
  • ????}??
  • }??
  • 測試類:

  • public?class?StrategyTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????String?exp?=?“8+8″;??
  • ????????AbstractCalculator?cal?=?new?Plus();??
  • ????????int?result?=?cal.calculate(exp,?“\\+”);??
  • ????????System.out.println(result);??
  • ????}??
  • }??
  • 我跟蹤下這個小程序的執行過程:首先將exp和”\\+”做參數,調用AbstractCalculator類里的 calculate(String,String)方法,在calculate(String,String)里調用同類的split(),之后再調用 calculate(int ,int)方法,從這個方法進入到子類中,執行完return num1 + num2后,將值返回到AbstractCalculator類,賦給result,打印出來。正好驗證了我們開頭的思路。

    15、觀察者模式(Observer)

    包括這個模式在內的接下來的四個模式,都是類和類之間的關系,不涉及到繼承,學的時候應該 記得歸納,記得本文最開始的那個圖。觀察者模式很好理解,類似于郵件訂閱和RSS訂閱,當我們瀏覽一些博客或wiki時,經常會看到RSS圖標,就這的意 思是,當你訂閱了該文章,如果后續有更新,會及時通知你。其實,簡單來講就一句話:當一個對象變化時,其它依賴該對象的對象都會收到通知,并且隨著變化! 對象之間是一種一對多的關系。先來看看關系圖:

    我解釋下這些類的作用:MySubject類就是我們的主對象,Observer1和Observer2是依賴于MySubject的對象,當 MySubject變化時,Observer1和Observer2必然變化。AbstractSubject類中定義著需要監控的對象列表,可以對其進 行修改:增加或刪除被監控對象,且當MySubject變化時,負責通知在列表內存在的對象。我們看實現代碼:

    一個Observer接口:

  • public?interface?Observer?{??
  • ????public?void?update();??
  • }??
  • 兩個實現類:

  • public?class?Observer1?implements?Observer?{??
  • ??
  • ????@Override??
  • ????public?void?update()?{??
  • ????????System.out.println(“observer1?has?received!”);??
  • ????}??
  • }??
  • public?class?Observer2?implements?Observer?{??
  • ??
  • ????@Override??
  • ????public?void?update()?{??
  • ????????System.out.println(“observer2?has?received!”);??
  • ????}??
  • ??
  • }??
  • Subject接口及實現類:

  • public?interface?Subject?{??
  • ??????
  • ????/*增加觀察者*/??
  • ????public?void?add(Observer?observer);??
  • ??????
  • ????/*刪除觀察者*/??
  • ????public?void?del(Observer?observer);??
  • ??????
  • ????/*通知所有的觀察者*/??
  • ????public?void?notifyObservers();??
  • ??????
  • ????/*自身的操作*/??
  • ????public?void?operation();??
  • }??
  • public?abstract?class?AbstractSubject?implements?Subject?{??
  • ??
  • ????private?Vector<Observer>?vector?=?new?Vector<Observer>();??
  • ????@Override??
  • ????public?void?add(Observer?observer)?{??
  • ????????vector.add(observer);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?del(Observer?observer)?{??
  • ????????vector.remove(observer);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?notifyObservers()?{??
  • ????????Enumeration<Observer>?enumo?=?vector.elements();??
  • ????????while(enumo.hasMoreElements()){??
  • ????????????enumo.nextElement().update();??
  • ????????}??
  • ????}??
  • }??
  • public?class?MySubject?extends?AbstractSubject?{??
  • ??
  • ????@Override??
  • ????public?void?operation()?{??
  • ????????System.out.println(“update?self!”);??
  • ????????notifyObservers();??
  • ????}??
  • ??
  • }??
  • 測試類:

  • public?class?ObserverTest?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Subject?sub?=?new?MySubject();??
  • ????????sub.add(new?Observer1());??
  • ????????sub.add(new?Observer2());??
  • ??????????
  • ????????sub.operation();??
  • ????}??
  • ??
  • }??
  • 輸出:

    update self! observer1 has received! observer2 has received!

    ?這些東西,其實不難,只是有些抽象,不太容易整體理解,建議讀者:根據關系圖,新建項目,自己寫代碼(或者參考我的代碼),按照總體思路走一遍,這樣才能體會它的思想,理解起來容易!?

    16、迭代子模式(Iterator)

    顧名思義,迭代器模式就是順序訪問聚集中的對象,一般來說,集合中非常常見,如果對集合類比較熟悉的話,理解本模式會十分輕松。這句話包含兩層意思:一是需要遍歷的對象,即聚集對象,二是迭代器對象,用于對聚集對象進行遍歷訪問。我們看下關系圖:

    ?

    這個思路和我們常用的一模一樣,MyCollection中定義了集合的一些操作,MyIterator中定義了一系列迭代操作,且持有Collection實例,我們來看看實現代碼:

    兩個接口:

  • public?interface?Collection?{??
  • ??????
  • ????public?Iterator?iterator();??
  • ??????
  • ????/*取得集合元素*/??
  • ????public?Object?get(int?i);??
  • ??????
  • ????/*取得集合大小*/??
  • ????public?int?size();??
  • }??
  • public?interface?Iterator?{??
  • ????//前移??
  • ????public?Object?previous();??
  • ??????
  • ????//后移??
  • ????public?Object?next();??
  • ????public?boolean?hasNext();??
  • ??????
  • ????//取得第一個元素??
  • ????public?Object?first();??
  • }??
  • 兩個實現:

  • public?class?MyCollection?implements?Collection?{??
  • ??
  • ????public?String?string[]?=?{“A”,”B”,”C”,”D”,”E”};??
  • ????@Override??
  • ????public?Iterator?iterator()?{??
  • ????????return?new?MyIterator(this);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?get(int?i)?{??
  • ????????return?string[i];??
  • ????}??
  • ??
  • ????@Override??
  • ????public?int?size()?{??
  • ????????return?string.length;??
  • ????}??
  • }??
  • public?class?MyIterator?implements?Iterator?{??
  • ??
  • ????private?Collection?collection;??
  • ????private?int?pos?=?-1;??
  • ??????
  • ????public?MyIterator(Collection?collection){??
  • ????????this.collection?=?collection;??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?Object?previous()?{??
  • ????????if(pos?>?0){??
  • ????????????pos–;??
  • ????????}??
  • ????????return?collection.get(pos);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?next()?{??
  • ????????if(pos<collection.size()-1){??
  • ????????????pos++;??
  • ????????}??
  • ????????return?collection.get(pos);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?boolean?hasNext()?{??
  • ????????if(pos<collection.size()-1){??
  • ????????????return?true;??
  • ????????}else{??
  • ????????????return?false;??
  • ????????}??
  • ????}??
  • ??
  • ????@Override??
  • ????public?Object?first()?{??
  • ????????pos?=?0;??
  • ????????return?collection.get(pos);??
  • ????}??
  • ??
  • }??
  • 測試類:

  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Collection?collection?=?new?MyCollection();??
  • ????????Iterator?it?=?collection.iterator();??
  • ??????????
  • ????????while(it.hasNext()){??
  • ????????????System.out.println(it.next());??
  • ????????}??
  • ????}??
  • }??
  • 輸出:A B C D E

    此處我們貌似模擬了一個集合類的過程,感覺是不是很爽?其實JDK中各個類也都是這些基本的東西,加一些設計模式,再加一些優化放到一起的,只要我們把這些東西學會了,掌握好了,我們也可以寫出自己的集合類,甚至框架!

    17、責任鏈模式(Chain of Responsibility) 接下 來我們將要談談責任鏈模式,有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。但是發 出者并不清楚到底最終那個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。先看看關系圖:

    ?

    Abstracthandler類提供了get和set方法,方便MyHandle類設置和修改引用對象,MyHandle類是核心,實例化后生成一系列相互持有的對象,構成一條鏈。

  • public?interface?Handler?{??
  • ????public?void?operator();??
  • }??
  • public?abstract?class?AbstractHandler?{??
  • ??????
  • ????private?Handler?handler;??
  • ??
  • ????public?Handler?getHandler()?{??
  • ????????return?handler;??
  • ????}??
  • ??
  • ????public?void?setHandler(Handler?handler)?{??
  • ????????this.handler?=?handler;??
  • ????}??
  • ??????
  • }??
  • public?class?MyHandler?extends?AbstractHandler?implements?Handler?{??
  • ??
  • ????private?String?name;??
  • ??
  • ????public?MyHandler(String?name)?{??
  • ????????this.name?=?name;??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?operator()?{??
  • ????????System.out.println(name+”deal!”);??
  • ????????if(getHandler()!=null){??
  • ????????????getHandler().operator();??
  • ????????}??
  • ????}??
  • }??
  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????MyHandler?h1?=?new?MyHandler(“h1″);??
  • ????????MyHandler?h2?=?new?MyHandler(“h2″);??
  • ????????MyHandler?h3?=?new?MyHandler(“h3″);??
  • ??
  • ????????h1.setHandler(h2);??
  • ????????h2.setHandler(h3);??
  • ??
  • ????????h1.operator();??
  • ????}??
  • }??
  • 輸出:

    h1deal! h2deal! h3deal!

    此處強調一點就是,鏈接上的請求可以是一條鏈,可以是一個樹,還可以是一個環,模式本身不約束這個,需要我們自己去實現,同時,在一個時刻,命令只允許由一個對象傳給另一個對象,而不允許傳給多個對象。

    ?18、命令模式(Command)

    命令模式很好理解,舉個例子,司令員下令讓士兵去干件事情,從整個事情的角度來考慮,司令員的作用是,發出口令,口令經過傳遞,傳到了士兵耳朵里, 士兵去執行。這個過程好在,三者相互解耦,任何一方都不用去依賴其他人,只需要做好自己的事兒就行,司令員要的是結果,不會去關注到底士兵是怎么實現的。 我們看看關系圖:

    Invoker是調用者(司令員),Receiver是被調用者(士兵),MyCommand是命令,實現了Command接口,持有接收對象,看實現代碼:

  • public?interface?Command?{??
  • ????public?void?exe();??
  • }??
  • public?class?MyCommand?implements?Command?{??
  • ??
  • ????private?Receiver?receiver;??
  • ??????
  • ????public?MyCommand(Receiver?receiver)?{??
  • ????????this.receiver?=?receiver;??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?exe()?{??
  • ????????receiver.action();??
  • ????}??
  • }??
  • public?class?Receiver?{??
  • ????public?void?action(){??
  • ????????System.out.println(“command?received!”);??
  • ????}??
  • }??
  • public?class?Invoker?{??
  • ??????
  • ????private?Command?command;??
  • ??????
  • ????public?Invoker(Command?command)?{??
  • ????????this.command?=?command;??
  • ????}??
  • ??
  • ????public?void?action(){??
  • ????????command.exe();??
  • ????}??
  • }??
  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Receiver?receiver?=?new?Receiver();??
  • ????????Command?cmd?=?new?MyCommand(receiver);??
  • ????????Invoker?invoker?=?new?Invoker(cmd);??
  • ????????invoker.action();??
  • ????}??
  • }??
  • 輸出:command received!

    這個很哈理解,命令模式的目的就是達到命令的發出者和執行者之間解耦,實現請求和執行分開,熟悉Struts的同學應該知道,Struts其實就是一種將請求和呈現分離的技術,其中必然涉及命令模式的思想!

    其實每個設計模式都是很重要的一種思想,看上去很熟,其實是因為我們在學到的東西中都有涉及,盡管有時我們并不知道,其實在Java本身的設計之中 處處都有體現,像AWT、JDBC、集合類、IO管道或者是Web框架,里面設計模式無處不在。因為我們篇幅有限,很難講每一個設計模式都講的很詳細,不 過我會盡我所能,盡量在有限的空間和篇幅內,把意思寫清楚了,更好讓大家明白。本章不出意外的話,應該是設計模式最后一講了,首先還是上一下上篇開頭的那 個圖:

    本章講講第三類和第四類。

    19、備忘錄模式(Memento)

    主要目的是保存一個對象的某個狀態,以便在適當的時候恢復對象,個人覺得叫備份模式更形象些,通俗的講下:假設有原始類A,A中有各種屬性,A可以 決定需要備份的屬性,備忘錄類B是用來存儲A的一些內部狀態,類C呢,就是一個用來存儲備忘錄的,且只能存儲,不能修改等操作。做個圖來分析一下:

    Original類是原始類,里面有需要保存的屬性value及創建一個備忘錄類,用來保存value值。Memento類是備忘錄類,Storage類是存儲備忘錄的類,持有Memento類的實例,該模式很好理解。直接看源碼:

  • public?class?Original?{??
  • ??????
  • ????private?String?value;??
  • ??????
  • ????public?String?getValue()?{??
  • ????????return?value;??
  • ????}??
  • ??
  • ????public?void?setValue(String?value)?{??
  • ????????this.value?=?value;??
  • ????}??
  • ??
  • ????public?Original(String?value)?{??
  • ????????this.value?=?value;??
  • ????}??
  • ??
  • ????public?Memento?createMemento(){??
  • ????????return?new?Memento(value);??
  • ????}??
  • ??????
  • ????public?void?restoreMemento(Memento?memento){??
  • ????????this.value?=?memento.getValue();??
  • ????}??
  • }??
  • public?class?Memento?{??
  • ??????
  • ????private?String?value;??
  • ??
  • ????public?Memento(String?value)?{??
  • ????????this.value?=?value;??
  • ????}??
  • ??
  • ????public?String?getValue()?{??
  • ????????return?value;??
  • ????}??
  • ??
  • ????public?void?setValue(String?value)?{??
  • ????????this.value?=?value;??
  • ????}??
  • }??
  • public?class?Storage?{??
  • ??????
  • ????private?Memento?memento;??
  • ??????
  • ????public?Storage(Memento?memento)?{??
  • ????????this.memento?=?memento;??
  • ????}??
  • ??
  • ????public?Memento?getMemento()?{??
  • ????????return?memento;??
  • ????}??
  • ??
  • ????public?void?setMemento(Memento?memento)?{??
  • ????????this.memento?=?memento;??
  • ????}??
  • }??
  • 測試類:

  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????//?創建原始類??
  • ????????Original?origi?=?new?Original(“egg”);??
  • ??
  • ????????//?創建備忘錄??
  • ????????Storage?storage?=?new?Storage(origi.createMemento());??
  • ??
  • ????????//?修改原始類的狀態??
  • ????????System.out.println(“初始化狀態為:”?+?origi.getValue());??
  • ????????origi.setValue(“niu”);??
  • ????????System.out.println(“修改后的狀態為:”?+?origi.getValue());??
  • ??
  • ????????//?回復原始類的狀態??
  • ????????origi.restoreMemento(storage.getMemento());??
  • ????????System.out.println(“恢復后的狀態為:”?+?origi.getValue());??
  • ????}??
  • }??
  • 輸出:

    初始化狀態為:egg 修改后的狀態為:niu 恢復后的狀態為:egg

    簡單描述下:新建原始類時,value被初始化為egg,后經過修改,將value的值置為niu,最后倒數第二行進行恢復狀態,結果成功恢復了。其實我覺得這個模式叫“備份-恢復”模式最形象。

    20、狀態模式(State)

    核心思想就是:當對象的狀態改變時,同時改變其行為,很好理解!就拿QQ來說,有幾種狀態,在線、隱身、忙碌等,每個狀態對應不同的操作,而且你的 好友也能看到你的狀態,所以,狀態模式就兩點:1、可以通過改變狀態來獲得不同的行為。2、你的好友能同時看到你的變化。看圖:

    State類是個狀態類,Context類可以實現切換,我們來看看代碼:

    ?package?com.xtfggef.dp.state;??

  • ??
  • /**?
  • ?*?狀態類的核心類?
  • ?*?2012-12-1?
  • ?*?@author?erqing?
  • ?*?
  • ?*/??
  • public?class?State?{??
  • ??????
  • ????private?String?value;??
  • ??????
  • ????public?String?getValue()?{??
  • ????????return?value;??
  • ????}??
  • ??
  • ????public?void?setValue(String?value)?{??
  • ????????this.value?=?value;??
  • ????}??
  • ??
  • ????public?void?method1(){??
  • ????????System.out.println(“execute?the?first?opt!”);??
  • ????}??
  • ??????
  • ????public?void?method2(){??
  • ????????System.out.println(“execute?the?second?opt!”);??
  • ????}??
  • }??
  • package?com.xtfggef.dp.state;??
  • ??
  • /**?
  • ?*?狀態模式的切換類???2012-12-1?
  • ?*?@author?erqing?
  • ?*??
  • ?*/??
  • public?class?Context?{??
  • ??
  • ????private?State?state;??
  • ??
  • ????public?Context(State?state)?{??
  • ????????this.state?=?state;??
  • ????}??
  • ??
  • ????public?State?getState()?{??
  • ????????return?state;??
  • ????}??
  • ??
  • ????public?void?setState(State?state)?{??
  • ????????this.state?=?state;??
  • ????}??
  • ??
  • ????public?void?method()?{??
  • ????????if?(state.getValue().equals(“state1″))?{??
  • ????????????state.method1();??
  • ????????}?else?if?(state.getValue().equals(“state2″))?{??
  • ????????????state.method2();??
  • ????????}??
  • ????}??
  • }??
  • 測試類:

    ? public?class?Test?{??

  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????State?state?=?new?State();??
  • ????????Context?context?=?new?Context(state);??
  • ??????????
  • ????????//設置第一種狀態??
  • ????????state.setValue(“state1″);??
  • ????????context.method();??
  • ??????????
  • ????????//設置第二種狀態??
  • ????????state.setValue(“state2″);??
  • ????????context.method();??
  • ????}??
  • }??
  • 輸出:

    execute the first opt! execute the second opt!

    根據這個特性,狀態模式在日常開發中用的挺多的,尤其是做網站的時候,我們有時希望根據對象的某一屬性,區別開他們的一些功能,比如說簡單的權限控制等。 21、訪問者模式(Visitor)

    訪問者模式把數據結構和作用于結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用于數據結構相對穩定算法又易變化的系統。因為訪問 者模式使得算法操作增加變得容易。若系統數據結構對象易于變化,經常有新的數據對象增加進來,則不適合使用訪問者模式。訪問者模式的優點是增加操作很容 易,因為增加操作意味著增加新的訪問者。訪問者模式將有關行為集中到一個訪問者對象中,其改變不影響系統數據結構。其缺點就是增加新的數據結構很困難。 —— From 百科

    簡單來說,訪問者模式就是一種分離對象數據結構與行為的方法,通過這種分離,可達到為一個被訪問者動態添加新的操作而無需做其它的修改的效果。簡單關系圖:

    來看看原碼:一個Visitor類,存放要訪問的對象,

  • public?interface?Visitor?{??
  • ????public?void?visit(Subject?sub);??
  • }??
  • public?class?MyVisitor?implements?Visitor?{??
  • ??
  • ????@Override??
  • ????public?void?visit(Subject?sub)?{??
  • ????????System.out.println(“visit?the?subject:”+sub.getSubject());??
  • ????}??
  • }??
  • Subject類,accept方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性,

  • public?interface?Subject?{??
  • ????public?void?accept(Visitor?visitor);??
  • ????public?String?getSubject();??
  • }??
  • public?class?MySubject?implements?Subject?{??
  • ??
  • ????@Override??
  • ????public?void?accept(Visitor?visitor)?{??
  • ????????visitor.visit(this);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?String?getSubject()?{??
  • ????????return?“love”;??
  • ????}??
  • }??
  • 測試:

  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ??????????
  • ????????Visitor?visitor?=?new?MyVisitor();??
  • ????????Subject?sub?=?new?MySubject();??
  • ????????sub.accept(visitor);??????
  • ????}??
  • }??
  • 輸出:visit the subject:love

    該模式適用場景:如果我們想為一個現有的類增加新功能,不得不考慮幾個事情:1、新功能會不會與現有功能出現兼容性問題?2、以后會不會再需要添 加?3、如果類不允許修改代碼怎么辦?面對這些問題,最好的解決方法就是使用訪問者模式,訪問者模式適用于數據結構相對穩定的系統,把數據結構和算法解 耦, 22、中介者模式(Mediator)

    中介者模式也是用來降低類類之間的耦合的,因為如果類類之間有依賴關系的話,不利于功能的拓展和維護,因為只要修改一個對象,其它關聯的對象都得進 行修改。如果使用中介者模式,只需關心和Mediator類的關系,具體類類之間的關系及調度交給Mediator就行,這有點像spring容器的作 用。先看看圖:

    User類統一接口,User1和User2分別是不同的對象,二者之間有關聯,如果不采用中介者模式,則需要二者相互持有引用,這樣二者的耦合度 很高,為了解耦,引入了Mediator類,提供統一接口,MyMediator為其實現類,里面持有User1和User2的實例,用來實現對 User1和User2的控制。這樣User1和User2兩個對象相互獨立,他們只需要保持好和Mediator之間的關系就行,剩下的全由 MyMediator類來維護!基本實現:

  • public?interface?Mediator?{??
  • ????public?void?createMediator();??
  • ????public?void?workAll();??
  • }??
  • public?class?MyMediator?implements?Mediator?{??
  • ??
  • ????private?User?user1;??
  • ????private?User?user2;??
  • ??????
  • ????public?User?getUser1()?{??
  • ????????return?user1;??
  • ????}??
  • ??
  • ????public?User?getUser2()?{??
  • ????????return?user2;??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?createMediator()?{??
  • ????????user1?=?new?User1(this);??
  • ????????user2?=?new?User2(this);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?workAll()?{??
  • ????????user1.work();??
  • ????????user2.work();??
  • ????}??
  • }??
  • public?abstract?class?User?{??
  • ??????
  • ????private?Mediator?mediator;??
  • ??????
  • ????public?Mediator?getMediator(){??
  • ????????return?mediator;??
  • ????}??
  • ??????
  • ????public?User(Mediator?mediator)?{??
  • ????????this.mediator?=?mediator;??
  • ????}??
  • ??
  • ????public?abstract?void?work();??
  • }??
  • public?class?User1?extends?User?{??
  • ??
  • ????public?User1(Mediator?mediator){??
  • ????????super(mediator);??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?void?work()?{??
  • ????????System.out.println(“user1?exe!”);??
  • ????}??
  • }??
  • public?class?User2?extends?User?{??
  • ??
  • ????public?User2(Mediator?mediator){??
  • ????????super(mediator);??
  • ????}??
  • ??????
  • ????@Override??
  • ????public?void?work()?{??
  • ????????System.out.println(“user2?exe!”);??
  • ????}??
  • }??
  • 測試類:

  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ????????Mediator?mediator?=?new?MyMediator();??
  • ????????mediator.createMediator();??
  • ????????mediator.workAll();??
  • ????}??
  • }??
  • 輸出:

    user1 exe! user2 exe! 23、解釋器模式(Interpreter) 解釋器模式是我們暫時的最后一講,一般主要應用在OOP開發中的編譯器的開發中,所以適用面比較窄。

    Context類是一個上下文環境類,Plus和Minus分別是用來計算的實現,代碼如下:

  • public?interface?Expression?{??
  • ????public?int?interpret(Context?context);??
  • }??
  • public?class?Plus?implements?Expression?{??
  • ??
  • ????@Override??
  • ????public?int?interpret(Context?context)?{??
  • ????????return?context.getNum1()+context.getNum2();??
  • ????}??
  • }??
  • public?class?Minus?implements?Expression?{??
  • ??
  • ????@Override??
  • ????public?int?interpret(Context?context)?{??
  • ????????return?context.getNum1()-context.getNum2();??
  • ????}??
  • }??
  • public?class?Context?{??
  • ??????
  • ????private?int?num1;??
  • ????private?int?num2;??
  • ??????
  • ????public?Context(int?num1,?int?num2)?{??
  • ????????this.num1?=?num1;??
  • ????????this.num2?=?num2;??
  • ????}??
  • ??????
  • ????public?int?getNum1()?{??
  • ????????return?num1;??
  • ????}??
  • ????public?void?setNum1(int?num1)?{??
  • ????????this.num1?=?num1;??
  • ????}??
  • ????public?int?getNum2()?{??
  • ????????return?num2;??
  • ????}??
  • ????public?void?setNum2(int?num2)?{??
  • ????????this.num2?=?num2;??
  • ????}??
  • ??????
  • ??????
  • }??
  • public?class?Test?{??
  • ??
  • ????public?static?void?main(String[]?args)?{??
  • ??
  • ????????//?計算9+2-8的值??
  • ????????int?result?=?new?Minus().interpret((new?Context(new?Plus()??
  • ????????????????.interpret(new?Context(9,?2)),?8)));??
  • ????????System.out.println(result);??
  • ????}??
  • }??
  • 最后輸出正確的結果:3。

    總結

    以上是生活随笔為你收集整理的java 23种设计模式及具体例子 收藏有时间慢慢看的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    亚洲精品97 | 91网站免费观看 | 日韩有码在线播放 | 国产免费小视频 | 国产 日韩 在线 亚洲 字幕 中文 | 日韩av影视在线观看 | av片在线观看 | 亚洲一二三久久 | 日韩精品一区在线播放 | 碰超人人| 色婷婷av国产精品 | 色综合咪咪久久网 | 国产成人精品亚洲 | 国产一区二区精品在线 | 日韩精品你懂的 | 中文乱幕日产无线码1区 | 国产小视频你懂的在线 | 99精品在线看 | 免费国产黄线在线观看视频 | 婷婷在线色 | 日韩大片在线 | 久久久精品国产一区二区 | 超碰在线官网 | 狠狠干干 | 久久婷婷视频 | 午夜精品福利一区二区 | 亚洲综合最新在线 | 国产精彩视频一区二区 | 精品国产乱码久久久久久浪潮 | 少妇按摩av | 日韩欧美一区视频 | 国产中出在线观看 | 黄污视频网站大全 | 碰超在线 | 久久综合日 | www.色午夜,com | 中文字幕五区 | 天天操人人干 | 欧美福利网站 | 国产亚洲欧美日韩高清 | 九九热在线精品 | 五月婷激情 | 久久国产精品一区二区三区四区 | 91亚洲精品久久久中文字幕 | 97超碰在线久草超碰在线观看 | 日韩精品一区二区在线视频 | 中文国产在线观看 | 2021国产视频 | 九九热中文字幕 | 一区二区三区电影 | 00av视频| 国产看片 色 | 国产福利免费在线观看 | 国产老熟 | 欧美九九九 | 午夜精品一区二区三区在线 | 天天干天天干天天干天天干天天干天天干 | 欧美不卡在线 | 天天狠狠干 | 五月天高清欧美mv | 亚洲欧洲精品一区二区 | 四川妇女搡bbbb搡bbbb搡 | 69精品视频 | 欧美日韩二三区 | 日韩xxx视频 | 国产在线播放一区二区 | 久久久精品免费观看 | 成人av动漫在线观看 | av视屏在线| 国产精品久久艹 | 日韩91在线 | 日韩免费视频播放 | 亚洲免费观看在线视频 | 日本动漫做毛片一区二区 | 成年人免费电影 | 亚洲国产wwwccc36天堂 | 中文字幕在线播放av | 99热国产精品 | www.国产视频 | 香蕉影院在线播放 | 欧美日韩中文在线观看 | aaa毛片视频| 日本一区二区三区免费看 | 欧美一级性生活视频 | 在线免费观看的av网站 | 精品国产亚洲日本 | 亚洲电影成人 | 天天爽人人爽夜夜爽 | 高清在线一区二区 | 中文字幕免费 | 91麻豆精品国产91久久久更新时间 | 91人人爱| 亚洲黄色软件 | 中文字幕第 | 国产美女精品在线 | 久草免费看 | 成人三级视频 | 国产精品久久久久久久妇 | 在线中文字幕视频 | 国产成人精品999 | 国产剧情一区二区 | 中国一区二区视频 | 国产精品免费不卡 | 国内外成人免费在线视频 | 国产精品毛片一区视频 | 亚洲精品视频大全 | 亚洲国产电影在线观看 | 久久综合狠狠综合久久综合88 | 中文字幕在线播放第一页 | 免费亚洲成人 | 国产精品成人免费精品自在线观看 | 亚洲一级黄色片 | 欧美在线视频精品 | 国产精品wwwwww| 国产精品视频免费 | 国产成人精品av | 欧美亚洲国产日韩 | 三日本三级少妇三级99 | 黄色软件网站在线观看 | 天天操天天射天天插 | 国产日韩欧美在线看 | 久草在线资源免费 | www久| 日韩欧美一级二级 | 免费看精品久久片 | 91在线国产观看 | 国产1级毛片 | 成人在线超碰 | 在线观看视频国产一区 | 亚洲va欧美va | 国产精品美女久久久网av | 女人高潮一级片 | 人人干天天射 | 天天综合网 天天综合色 | 久久久久久久99精品免费观看 | 成人性生交大片免费观看网站 | 日韩在线观看不卡 | 国产探花视频在线播放 | 91香蕉视频在线下载 | 99免费在线观看 | 欧美不卡在线 | 日韩色在线观看 | 中文网丁香综合网 | 中文字幕网站视频在线 | 国际精品久久久 | 在线中文字幕网站 | 日韩免费在线视频观看 | 国产原创在线观看 | 香蕉一区 | 色综合久久久久久中文网 | 国产黄在线免费观看 | 九色在线视频 | 日韩69视频 | 欧美在线观看视频一区二区三区 | 亚洲成av人影院 | 久久久久人人 | 国产精品黄色在线观看 | 久久久久国产精品视频 | 久久理论电影网 | 欧美做受69 | 国产在线视频一区二区三区 | 欧美资源在线观看 | 亚洲丝袜一区 | 亚州成人av在线 | 日韩精品一区二区三区免费观看 | 天天射天天干天天 | 人人澡超碰碰97碰碰碰软件 | 麻豆精品传媒视频 | 精品国产伦一区二区三区观看说明 | 一二三区视频在线 | 丁香九月婷婷综合 | 亚洲狠狠 | 97精品一区| 久操伊人 | 91免费在线播放 | 亚洲无毛专区 | 欧美老人xxxx18 | 亚洲精品18日本一区app | 亚洲成a人片在线www | 97视频免费观看 | av黄在线播放 | 久久久久国产精品午夜一区 | 久在线| 色五婷婷 | 欧美天天综合网 | 日本九九视频 | 婷婷丁香九月 | 色婷婷导航 | 狠狠干成人 | 久久九九精品久久 | 免费在线a | 欧美大码xxxx | 亚洲视频久久久久 | 99久久爱| 国内精品久久久久久久久久清纯 | 中文理论片 | 免费看片成人 | 亚洲综合激情网 | 欧美性脚交 | 在线岛国av | 国产亚洲综合性久久久影院 | 黄色福利网站 | 亚洲欧美怡红院 | 成人毛片一区 | 欧美淫aaa免费观看 日韩激情免费视频 | 99精品免费久久久久久久久日本 | 国产一区二区三区在线免费观看 | 欧美日韩性视频在线 | 九九精品久久 | 日韩av网站在线播放 | 日本精品va在线观看 | 狠狠的操狠狠的干 | 日韩大片在线观看 | 亚洲一区美女视频在线观看免费 | 久久久香蕉视频 | 久久久久国产一区二区三区 | 国产精品女教师 | 九九热免费视频在线观看 | 国产91精品高清一区二区三区 | 欧美亚洲精品在线观看 | 久草免费手机视频 | 日韩在线欧美在线 | 国产一区久久久 | www.天天操.com | 91高清免费 | 天天操综合网站 | 99精品福利 | 国产免费成人 | 国产精品对白一区二区三区 | 天天操天天能 | 久久成人欧美 | www最近高清中文国语在线观看 | 久久狠狠亚洲综合 | 亚洲最大av网 | 91久久黄色 | 中文字幕美女免费在线 | 一级片黄色片网站 | 久久一线 | 久久精品视频免费观看 | 视频 天天草 | 日本 在线 视频 中文 有码 | av免费观看高清 | 国产夫妻性生活自拍 | 亚洲三级国产 | 日韩精品黄 | 韩日av在线| 99精品欧美一区二区三区黑人哦 | 在线欧美a | 久久久国产精品久久久 | 99在线精品观看 | 福利视频入口 | 2022国产精品视频 | 日本精品视频网站 | 日韩在线免费看 | 91av视频在线观看免费 | 国产美女网站在线观看 | 日韩啪啪小视频 | 婷婷六月综合网 | 91麻豆免费看 | 国产精品毛片 | 日日夜夜精品视频天天综合网 | 91黄色视屏 | 99精品在线免费视频 | 国产免费久久精品 | 国产精品久久久免费 | 91爱爱视频| 中日韩三级视频 | www中文在线| 欧美视频www | 一区二区中文字幕在线 | avav片 | 日韩av手机在线观看 | 久久这里只有精品久久 | 西西人体www444 | 日日夜夜精品免费观看 | 一区二区在线影院 | 日韩三级av | 国产高清免费观看 | 在线综合 亚洲 欧美在线视频 | 国产精品va在线观看入 | 婷婷丁香九月 | 免费在线观看av | 人人草人人草 | 成人影音在线 | 成人av日韩| 免费男女网站 | 9幺看片| 午夜视频久久久 | 91精品专区 | 青青久视频 | 久久中文精品视频 | 五月婷婷综合激情 | 国产成人精品电影久久久 | 99精品视频免费看 | 一本一道久久a久久精品蜜桃 | 在线观看视频日韩 | 极品美女被弄高潮视频网站 | 又黄又爽的免费高潮视频 | 中文字幕无吗 | 精品久久久久久一区二区里番 | 国产精品一区一区三区 | 日韩区在线观看 | 成人小视频在线观看免费 | 天天伊人狠狠 | 午夜久久久久久久久 | 日韩免费区 | 国产精品资源网 | 在线视频91 | 国产精品福利在线播放 | 中文字幕av在线免费 | 久久久影院官网 | 日韩高清不卡一区二区三区 | 亚洲国产免费看 | 欧美日韩亚洲在线 | 亚洲3级 | 丁香视频全集免费观看 | 精品免费在线视频 | 中文字幕免费成人 | 日韩欧美一二三 | 午夜精品久久久久久久99无限制 | 午夜.dj高清免费观看视频 | 欧美日韩免费网站 | 欧美孕妇视频 | 国产精品永久在线观看 | 日韩一区二区免费在线观看 | a级国产乱理伦片在线观看 亚洲3级 | 91精品在线视频 | 久久综合色播五月 | 亚洲综合黄色 | 精品国产综合区久久久久久 | 日本二区三区在线 | 久久在线观看 | 久久免费视频这里只有精品 | 国产黄色电影 | 97理论电影 | 97视频免费在线观看 | 日日夜夜骑| 欧美色噜噜噜 | 日韩精品一区二 | 国产精品久久久久永久免费观看 | 免费黄色激情视频 | 97视频在线播放 | 国内小视频在线观看 | 亚洲成人精品国产 | 日韩激情视频在线 | 超碰在97 | 久久狠狠一本精品综合网 | 99国产精品一区 | 一区二区三区久久 | 久在线观看视频 | 在线观看你懂的网址 | 久久成人欧美 | 国产精品一区二区免费视频 | 日韩中文在线电影 | 91麻豆精品国产91久久久使用方法 | 国产精品麻豆视频 | 欧美激情视频一区 | 中文区中文字幕免费看 | 久久成人精品电影 | 波多野结衣视频在线 | 国产精品xxxx18a99 | 黄色片网站| 国产精品男女视频 | 久久视频精品在线观看 | 国产在线观看高清视频 | 蜜桃久久久 | 夜夜爱av | 伊人黄色网 | 日韩在线观看一区 | 五月天av在线 | 亚洲国产精品女人久久久 | 国产激情电影综合在线看 | 国产亚洲精品日韩在线tv黄 | 婷婷六月网| 欧美视频在线观看免费网址 | 日本中文乱码卡一卡二新区 | 亚洲精品成人av在线 | 99999精品 | 日韩av中文在线 | 超碰97人人干 | 国产成人免费观看久久久 | 亚洲动漫在线观看 | 国产精品国产毛片 | 久久久九色精品国产一区二区三区 | 毛片网在线播放 | 人人网av | 美女网站色免费 | 欧美综合国产 | 2021av在线| 日本黄区免费视频观看 | 天天干天天草 | 国产欧美最新羞羞视频在线观看 | 国产xxxxx在线观看 | 亚洲夜夜网 | 国产精品一区二区在线播放 | 色婷婷电影 | 久久中文欧美 | 精品一区91| 91香蕉国产在线观看软件 | 国产人成在线视频 | 亚洲综合色丁香婷婷六月图片 | 在线免费色 | 国产精品久久久久久久久久久久冷 | 午夜在线免费视频 | 久草在线中文888 | 久久香蕉国产 | 一级性生活片 | 手机在线黄色网址 | 99精品视频免费看 | 天天天操天天天干 | 亚洲永久国产精品 | 黄色片视频免费 | 成人av教育 | 午夜18视频在线观看 | 日韩精品免费在线视频 | 国产精品久久久久国产精品日日 | 激情五月播播久久久精品 | 夜夜天天干 | 日本中文字幕在线看 | 国产爽视频 | 麻豆91在线| 国产精品精品国产婷婷这里av | 亚洲国产精品影院 | 免费看黄在线观看 | 日韩中文幕 | 日韩欧美精品在线观看视频 | 日本成址在线观看 | 99视频久| 国产69久久久欧美一级 | 日本黄色免费播放 | 一级黄色片在线免费看 | 国产亚洲午夜高清国产拍精品 | 日本黄色免费大片 | 深夜福利视频在线观看 | 正在播放亚洲精品 | 特黄特色特刺激视频免费播放 | 狠狠地操 | 夜夜爽天天爽 | 国产成人性色生活片 | 成人久久久久 | 亚洲另类视频在线 | 国产欧美三级 | 天天狠狠 | 亚洲精品视频在线观看免费视频 | 欧美日韩亚洲在线观看 | 九九热在线精品视频 | 亚洲 欧美日韩 国产 中文 | 国产中文自拍 | 91福利视频久久久久 | 亚洲视频国产 | 在线免费高清 | 国产伦理久久精品久久久久_ | 2020天天干夜夜爽 | 99精品一级欧美片免费播放 | 亚洲更新最快 | 在线看片日韩 | 综合激情久久 | 黄色软件视频网站 | 一区二区三区动漫 | 激情av资源 | 香蕉在线视频观看 | 黄色免费网站下载 | 成人午夜av电影 | 欧美成人精品三级在线观看播放 | 欧美大片在线看免费观看 | 色天堂在线视频 | 在线观看视频一区二区三区 | 99久久国产免费看 | 在线香蕉视频 | 亚洲午夜久久久久久久久电影网 | 国产 日韩 欧美 中文 在线播放 | 高清有码中文字幕 | 中文字幕在线观看国产 | 91中文在线 | 欧洲一区二区三区精品 | 色婷婷六月天 | 国产一级视频在线观看 | 久久亚洲婷婷 | 国产色视频网站 | 丁香5月婷婷 | 在线视频 一区二区 | 在线视频免费观看 | 一区二区av | 国产精品美女免费看 | 国产特级毛片aaaaaaa高清 | 成人小视频在线免费观看 | 黄色国产在线观看 | 久久综合色8888 | 天天摸天天操天天爽 | 天天操福利视频 | 日本中文字幕在线电影 | 99国产精品久久久久老师 | 高清免费av在线 | 天天玩天天干 | 国产麻豆视频在线观看 | 欧美激情精品久久久久久免费 | 欧美日韩二区三区 | 手机色站| 免费99| 色先锋资源网 | 久久国产精彩视频 | 久久天天躁夜夜躁狠狠85麻豆 | 麻豆94tv免费版 | 色综合久久久久综合体桃花网 | 久久少妇免费视频 | 最新久久免费视频 | 国产白浆在线观看 | 99免费在线观看 | 涩涩网站在线看 | 日韩久久精品一区二区三区下载 | 在线观看av大片 | 91福利试看| www.色婷婷.com| 日本精品二区 | 日韩动态视频 | 99草视频在线观看 | 99视频精品全部免费 在线 | 最近能播放的中文字幕 | 在线日韩av | 99精品在线观看视频 | 免费在线观看视频一区 | 四虎www.| 成人一级片免费看 | 黄色小说在线免费观看 | 精品在线小视频 | 在线观看中文字幕dvd播放 | 欧美久久久久久久久久久久久 | 婷婷深爱| 成年美女黄网站色大片免费看 | 国产精品高清在线观看 | 麻豆久久一区二区 | 在线观看91网站 | 免费国产在线视频 | 天天爽夜夜操 | 日韩专区av| av大全在线免费观看 | 五月婷婷视频在线观看 | 99久精品视频 | 久草精品在线观看 | 日韩色综合网 | 亚洲jizzjizz日本少妇 | 成人香蕉视频 | 久草在线 | 99精品欧美一区二区三区 | 91精品久久久久久粉嫩 | 久久精品一二三区 | 国产精品自产拍在线观看蜜 | 亚洲最新视频在线播放 | 日韩欧美电影 | 国产色久 | av不卡免费在线观看 | 亚洲午夜精品久久久久久久久久久久 | 一本一本久久a久久精品牛牛影视 | 国产成人99av超碰超爽 | 亚洲综合视频在线播放 | 在线观看成人av | 九九九免费视频 | 亚洲人视频在线 | 一级片免费在线 | 欧美精品在线视频 | 香蕉久久久久 | 亚洲综合爱 | 久久国内精品视频 | av韩国在线 | 欧美91成人网 | 在线观看黄网站 | 婷婷色社区| 天天操网站| 午夜精品久久久99热福利 | 久久久久99精品国产片 | 亚洲精品在线一区二区三区 | 日韩欧美大片免费观看 | 久久电影国产免费久久电影 | 九九九九色 | 国产精品视频观看 | 色综合天天射 | 永久免费毛片在线观看 | 亚洲精品ww | 日韩剧| 久久久精华网 | 久久国产99| 一区二区三区在线播放 | 国产高清视频在线播放 | 超碰人人在线 | 亚洲国产精品成人精品 | 五月天电影免费在线观看一区 | 免费看网站在线 | 不卡电影一区二区三区 | 国产欧美日韩精品一区二区免费 | 五月天丁香视频 | 五月婷婷综合网 | 岛国av在线不卡 | 99国产精品久久久久久久久久 | 中文字幕免费一区二区 | 久久久久亚洲最大xxxx | 亚洲日本精品视频 | 探花视频在线观看 | 香蕉视频在线免费看 | 丁香花在线视频观看免费 | 黄视频网站大全 | 国产精品久久久久久久av大片 | 亚洲视频在线观看免费 | 国产精品高潮呻吟久久久久 | 91麻豆精品国产91久久久久 | 欧美国产日韩一区二区 | 国内精品久久久久久久久久久久 | 久草a视频| 国产乱码精品一区二区三区介绍 | 久久久久久电影 | 在线免费观看视频一区 | 黄色www | 最新色视频 | 国产香蕉在线 | 久久 一区 | 在线观看视频99 | 日韩电影在线观看一区 | 午夜婷婷在线观看 | 手机av网站| 少妇自拍av| 一区二区三区av在线 | 成人午夜电影在线 | 在线韩国电影免费观影完整版 | 亚洲精品综合一二三区在线观看 | 免费观看一级成人毛片 | 久久久久久黄色 | 精品日本视频 | 国产91精品看黄网站 | 日日躁天天躁 | 亚洲天天做| 天天操婷婷| 成人亚洲欧美 | bbb搡bbb爽爽爽 | 日韩高清一二区 | 欧美日韩一区三区 | 免费观看一级成人毛片 | 欧美日韩在线精品 | 精品高清视频 | 国产亚洲一区 | 欧美国产精品久久久久久免费 | 中文字幕亚洲高清 | 日韩黄视频| av在线色| 日韩精品观看 | 五月天综合色 | 久草观看视频 | 欧美巨大 | 国产精品久久久久婷婷二区次 | 国产精品密入口果冻 | 日躁夜躁狠狠躁2001 | 人人澡超碰碰97碰碰碰软件 | 国产黄色电影 | 成人午夜在线观看 | 四虎在线免费观看视频 | 黄色大片免费播放 | 黄色成人影视 | 五月天激情综合网 | 国产福利av在线 | 日韩精品视频在线观看免费 | 一级精品视频在线观看宜春院 | 国产精品免费在线观看视频 | 在线看国产 | 精品久久久久国产 | 黄色一区三区 | 国产另类av | 久久精品国产一区二区电影 | 四虎影视成人精品国库在线观看 | 国产福利一区二区三区在线观看 | 99久久99久久精品国产片果冰 | 国产三级精品三级在线观看 | 天天综合久久综合 | 久亚洲 | av在线免费网站 | 精品福利视频在线观看 | jizz999| 黄色a一级视频 | 免费高清在线观看电视网站 | 在线观看视频国产 | 免费日韩av电影 | www.香蕉视频 | 国内精品亚洲 | 免费观看av | 国产精品99蜜臀久久不卡二区 | 日韩av有码在线 | 在线观看的av网站 | 久久国产精品影视 | 国产探花| 久久在线免费观看 | 麻豆你懂的 | 1024在线看片 | 亚洲视频axxx| 国内偷拍精品视频 | 超碰在线色 | 国产精品一区二区三区免费视频 | 国产清纯在线 | 97超碰人人澡 | 久久综合一本 | 日韩剧情 | 91在线永久 | 蜜臀av在线一区二区三区 | 婷婷精品视频 | 在线观看免费一级片 | 久草视频99 | 亚洲国产中文字幕在线视频综合 | 1024手机在线看 | 丁香5月婷婷久久 | 国产亚洲婷婷免费 | 91高清不卡 | 久久蜜臀av | 欧美99热 | 男女免费视频观看 | 国产一级做a爱片久久毛片a | 日本精品久久久久影院 | 国产免费观看久久黄 | 久久亚洲专区 | 曰本免费av | 天天干天天射天天爽 | 国产视频美女 | 国产午夜精品理论片在线 | 中文字幕在线网 | 日韩中文字幕亚洲一区二区va在线 | 三上悠亚一区二区在线观看 | 一区二区三区四区精品 | .精品久久久麻豆国产精品 亚洲va欧美 | 久久久久亚洲国产精品 | 成人av.com | 国精产品满18岁在线 | 婷婷综合电影 | 丁香婷婷自拍 | 色在线网站 | 一区二区国产精品 | 日韩国产欧美在线视频 | 久久精品日产第一区二区三区乱码 | 97精品视频在线播放 | 日韩在线视频播放 | 日韩在线观看不卡 | 亚洲成 人精品 | 水蜜桃亚洲一二三四在线 | 综合中文字幕 | 久艹在线观看视频 | 国产精品麻豆三级一区视频 | 97精品在线视频 | 99热精品国产 | 毛片网在线播放 | 婷婷在线精品视频 | 国产小视频你懂的 | 五月色综合 | 精品一区电影 | 久草视频免费看 | 久久国产剧场电影 | 玖玖在线看 | 91精品办公室少妇高潮对白 | 夜夜澡人模人人添人人看 | 久久在线影院 | 亚洲精品乱码久久久久久蜜桃欧美 | 成人黄色毛片视频 | 亚洲精品免费在线观看视频 | 国产精品自在线拍国产 | 精品国产自 | 91正在播放 | 一区二区三区中文字幕在线 | 成人免费亚洲 | 国产小视频免费在线网址 | 国内久久久久 | 日韩av中文在线 | 成人高清在线观看 | 欧美一级视频免费 | 午夜影院在线观看18 | 一区二区三区国产欧美 | 久久久久久久久久久久久久电影 | 日韩视频一 | 天天射,天天干 | 欧美综合色在线图区 | 欧洲黄色片 | 国产黄色av| 亚洲免费高清视频 | 一级黄色a视频 | 免费亚洲视频在线观看 | 日韩精品国产一区 | 国产一区欧美日韩 | 五月激情五月激情 | av官网在线 | 人人草在线视频 | 久久久精品小视频 | 国产精品久久久久久久久费观看 | 国产成人精品日本亚洲999 | 激情偷乱人伦小说视频在线观看 | 中文字幕一区在线观看视频 | 91中文在线视频 | 久久成人国产精品 | 久久免费视频3 | 国产黄色播放 | 久久综合久久综合这里只有精品 | 国产精品一区免费在线观看 | 美女网站视频免费黄 | 深爱综合网 | 天天操天天操天天操天天操天天操天天操 | 久草网在线观看 | 日本黄色免费网站 | 97成人精品区在线播放 | 欧美日韩一区二区视频在线观看 | 中文在线a√在线 | 91理论片午午伦夜理片久久 | 免费亚洲成人 | 三级黄色免费 | 日日操天天操夜夜操 | 国产精品久久久久婷婷 | 天天干一干 | 超碰人人99| 日韩啪视频 | 免费又黄又爽的视频 | 91精品国产乱码久久 | 偷拍精偷拍精品欧洲亚洲网站 | 欧美精品资源 | 午夜视频久久久 | 久久精品国产精品 | 日日爱网站 | 视频国产在线观看18 | 91精品国产高清自在线观看 | 婷婷丁香九月 | 国产精品永久久久久久久久久 | 成年人在线观看 | 免费高清在线视频一区· | 国内精品久久久久影院日本资源 | 日韩精品视频免费 | 一区二区三区国产欧美 | 亚洲欧美日韩一二三区 | 久久69av | 国产精品永久久久久久久久久 | 97超碰总站 | 欧美日韩视频免费看 | 黄p网站在线观看 | 亚州成人av在线 | 97超碰中文字幕 | 天天翘av | 日韩三级免费观看 | 国产精品涩涩屋www在线观看 | 四虎成人精品永久免费av | 伊人狠狠色丁香婷婷综合 | 天堂网一区 | 亚洲精选视频免费看 | 一区二区三区视频在线 | 天天色天天搞 | 成年人免费看 | 999成人| 久久久国产电影 | www夜夜操com | 久久99精品国产一区二区三区 | 成人精品国产免费网站 | 中文字幕在线视频网站 | 久久视频免费在线 | 久久国产午夜精品理论片最新版本 | 在线免费视频你懂的 | 草久视频在线 | 五月激情婷婷丁香 | 日韩免费中文 | 黄色a级片在线观看 | 国产中文伊人 | 久久精品草 | 国产免费久久av | 久久久久久视频 | 91看片淫黄大片一级在线观看 | 久久综合中文色婷婷 | 中文av免费 | 国产破处在线视频 | 国产视频在线观看一区二区 | 99久久久久久久 | 午夜久久久精品 | 国产黄色免费电影 | 久久99国产一区二区三区 | 天天射天 | 99久久久久久久 | 久久蜜臀av | www视频在线播放 | 色就色,综合激情 | 亚洲国产字幕 | 波多野结衣在线观看视频 | 天天色成人 | 亚洲精品小区久久久久久 | 久久www免费视频 | 日韩在线色视频 | 日本韩国精品一区二区在线观看 | 欧洲激情综合 | 四虎国产精品成人免费4hu | 91精品国产综合久久婷婷香蕉 | 久久99精品国产99久久6尤 | 午夜精品一区二区三区免费 | 久久精品免费播放 | 日韩国产高清在线 | 久久免费黄色大片 | 五月天六月婷 | 婷婷激情综合网 | 久久色中文字幕 | 国产精品大尺度 | 成av人电影| 99久久99久国产黄毛片 | 日韩精品一区二区免费视频 | 五月婷婷电影网 | 性色av免费看| 亚洲精品国产精品国自产 | 99久久日韩精品免费热麻豆美女 | 丝袜网站在线观看 | 九九九国产| 天堂va欧美va亚洲va老司机 | 免费在线国产黄色 | 国产一区精品在线观看 | 日韩网页 | 亚洲欧美成人 | 午夜久久成人 | 国产成人免费 | 午夜12点 | 在线a亚洲视频播放在线观看 | 色偷偷88888欧美精品久久 | 免费福利在线播放 | 九九热只有这里有精品 | 精品国产资源 | 精品久操 | 国产午夜精品久久久久久久久久 | 99r在线观看| 国产精品视频免费在线观看 | 日韩大片在线免费观看 | 国产精品一区二区在线 | 国产一级a毛片视频爆浆 | 中文字幕免费观看全部电影 | 国产成年人av | 久久99精品久久久久久秒播蜜臀 | 9在线观看免费高清完整版在线观看明 | 免费在线观看国产精品 | 欧美xxxx性xxxxx高清 | 欧美日韩精品在线一区二区 | 日韩中文字幕国产 | 99爱这里只有精品 | 日韩av伦理片| 久久久久这里只有精品 | 国产欧美高清 | 色狠狠一区二区 | 日韩高清无线码2023 | 亚洲精品黄色在线观看 | 亚洲一级久久 | 午夜电影久久久 | 国产精品毛片久久久久久久 | av在线a | 日韩电影精品 | 中文字幕影片免费在线观看 | 欧美analxxxx | 激情丁香5月 | 成人中文字幕av | 女人18片| 亚洲国产精品成人精品 | 91成人免费看 | 久久久精品久久日韩一区综合 | 天天爱天天射 | 国产午夜麻豆影院在线观看 | 亚洲国产av精品毛片鲁大师 | 欧美日韩国产在线观看 | 久久久影片 | 91麻豆精品国产91久久久使用方法 | 日韩在线小视频 | 在线观看视频免费播放 | 麻豆精品传媒视频 | 五月婷婷色综合 | 人人干人人爽 | 91在线免费播放 | 一区二区理论片 | 日韩超碰在线 | 成人免费视频免费观看 | 天天爱天天色 | 亚洲婷婷伊人 | www色com | 黄色成人影视 | 91精品在线免费观看视频 | 五月婷婷丁香六月 | 亚洲作爱视频 | 最新中文字幕在线播放 | 久免费视频 | 日本三级中文字幕在线观看 | 国产精品涩涩屋www在线观看 | 999久久久久久久久6666 | japanesexxxhd奶水| www.成人sex| 亚洲精品在线网站 | 国产精品亚洲精品 | 欧美 日韩 久久 | 日韩综合一区二区三区 | 奇米影视777四色米奇影院 | 欧美一级专区免费大片 | 四虎在线免费视频 | 国产精品久久久久久一区二区 | 最新极品jizzhd欧美 | 久久综合九色欧美综合狠狠 | 午夜av剧场 | 欧美粗又大 | 亚洲精品一区二区三区在线观看 | 99成人在线视频 | 手机在线观看国产精品 | 国产视频亚洲精品 | 中文字幕在线看视频国产 | 久久丁香网 | 成年人免费在线观看网站 |