日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

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

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

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

一、設(shè)計模式的分類

總體來說設(shè)計模式分為三大類:

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

結(jié)構(gòu)型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

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

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

二、Java的23中設(shè)計模式

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

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

工廠方法模式分為三種:

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

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

首先,創(chuàng)建二者的共同接口:

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

  • 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、多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創(chuàng)建對象,而多個工廠方法模式是提供多個工廠方法,分別創(chuàng)建對象。關(guān)系圖:

    ::__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、靜態(tài)工廠方法模式,將上面的多個工廠方法模式里的方法置為靜態(tài)的,不需要創(chuàng)建實例,直接調(diào)用即可。

  • 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!

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

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

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

    請看例子:

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

  • 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();??
  • ????}??
  • }??
  • 其實這個模式的好處就是,如果你現(xiàn)在想增加一個功能:發(fā)及時信息,則只需做一個實現(xiàn)類,實現(xiàn)Sender接口,同時做一個工廠類,實現(xiàn)Provider接口,就OK了,無需去改動現(xiàn)成的代碼。這樣做,拓展性較好!

    3、單例模式(Singleton

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

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

    2、省去了new操作符,降低了系統(tǒng)內(nèi)存的使用頻率,減輕GC壓力。

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 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;??
  • ????}??
  • }??
  • 考慮性能的話,整個程序只需創(chuàng)建一次實例,所以性能也不會有什么影響。

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

  • 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();??
  • ????}??
  • }??
  • 通過單例模式的學(xué)習(xí)告訴我們:

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

    2、synchronized關(guān)鍵字鎖定的是對象,在用的時候,一定要在恰當(dāng)?shù)牡胤绞褂?#xff08;注意需要使用鎖的對象和過程,可能有的時候并不是整個對象及整個過程都需要鎖)。

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

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

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

    再次,單例類可以被繼承,他的方法可以被覆寫。但是靜態(tài)類內(nèi)部方法都是static,無法被覆寫。

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

    4、建造者模式(Builder)

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

    還和前面一樣,一個Sender接口,兩個實現(xiàn)類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);??
  • ????}??
  • }??
  • 從這點看出,建造者模式將很多功能集成到一個類里,這個類可以創(chuàng)造出比較復(fù)雜的東西。所以與工程模式的區(qū)別就是:工廠模式關(guān)注的是創(chuàng)建單個產(chǎn)品,而建造者模式則關(guān)注創(chuàng)建符合對象,多個部分。因此,是選擇工廠模式還是建造者模式,依實際情況而定。

    5、原型模式(Prototype)

    原型模式雖然是創(chuàng)建型的模式,但是與工程模式?jīng)]有關(guān)系,從名字即可看出,該模式的思想就是將一個對象作為原型,對其進行復(fù)制、克隆,產(chǎn)生一個和原對象類似的新對象。本小結(jié)會通過對象的復(fù)制,進行講解。在Java中,復(fù)制對象是通過clone()實現(xiàn)的,先創(chuàng)建一個原型類:

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

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

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

    此處,寫一個深淺復(fù)制的例子:

  • public?class?Prototype?implements?Cloneable,?Serializable?{??
  • ??
  • ????private?static?final?long?serialVersionUID?=?1L;??
  • ????private?String?string;??
  • ??
  • ????private?SerializableObject?obj;??
  • ??
  • ????/*?淺復(fù)制?*/??
  • ????public?Object?clone()?throws?CloneNotSupportedException?{??
  • ????????Prototype?proto?=?(Prototype)?super.clone();??
  • ????????return?proto;??
  • ????}??
  • ??
  • ????/*?深復(fù)制?*/??
  • ????public?Object?deepClone()?throws?IOException,?ClassNotFoundException?{??
  • ??
  • ????????/*?寫入當(dāng)前對象的二進制流?*/??
  • ????????ByteArrayOutputStream?bos?=?new?ByteArrayOutputStream();??
  • ????????ObjectOutputStream?oos?=?new?ObjectOutputStream(bos);??
  • ????????oos.writeObject(this);??
  • ??
  • ????????/*?讀出二進制流產(chǎn)生的新對象?*/??
  • ????????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;??
  • }??
  • 要實現(xiàn)深復(fù)制,需要采用流的形式讀入當(dāng)前對象的二進制輸入,再寫出二進制數(shù)據(jù)對應(yīng)的對象。

    7種結(jié)構(gòu)型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

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

    核心思想就是:有一個Source類,擁有一個方法,待適配,目標(biāo)接口時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類,實現(xiàn)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接口的實現(xiàn)類就具有了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();??
  • ????}??
  • }??
  • 輸出與第一種一樣,只是適配的方法不同而已。

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

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

  • 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!

    達到了我們的效果!

    ?講了這么多,總結(jié)一下三種適配器模式的應(yīng)用場景:

    類的適配器模式:當(dāng)希望將一個類轉(zhuǎn)換成滿足另一個新接口的類時,可以使用類的適配器模式,創(chuàng)建一個新類,繼承原有的類,實現(xiàn)新的接口即可。

    對象的適配器模式:當(dāng)希望將一個對象轉(zhuǎn)換成滿足另一個新接口的對象時,可以創(chuàng)建一個Wrapper類,持有原類的一個實例,在Wrapper類的方法中,調(diào)用實例的方法就行。

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

    7、裝飾模式(Decorator)

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

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

  • 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!

    裝飾器模式的應(yīng)用場景:

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

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

    缺點:產(chǎn)生過多相似的對象,不易排錯!

    8、代理模式(Proxy)

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

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

  • 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!

    代理模式的應(yīng)用場景:

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

    1、修改原有的方法來適應(yīng)。這樣違反了“對擴展開放,對修改關(guān)閉”的原則。

    2、就是采用一個代理類調(diào)用原有的方法,且對產(chǎn)生的結(jié)果進行控制。這種方法就是代理模式。

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

    9、外觀模式(Facade)

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

    我們先看下實現(xiàn)類:

  • 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他們之間將會相互持有實例,產(chǎn)生關(guān)系,這樣會造成嚴(yán)重的依賴,修改一個類, 可能會帶來其他類的修改,這不是我們想要看到的,有了Computer類,他們之間的關(guān)系被放在了Computer類里,這樣就起到了解耦的作用,這,就 是外觀模式!

    10、橋接模式(Bridge)

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

    實現(xiàn)代碼:

    先定義接口:

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

  • 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();??
  • ??????????
  • ????????/*調(diào)用第一個對象*/??
  • ????????Sourceable?source1?=?new?SourceSub1();??
  • ????????bridge.setSource(source1);??
  • ????????bridge.method();??
  • ??????????
  • ????????/*調(diào)用第二個對象*/??
  • ????????Sourceable?source2?=?new?SourceSub2();??
  • ????????bridge.setSource(source2);??
  • ????????bridge.method();??
  • ????}??
  • }??
  • output:

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

    這樣,就通過對Bridge類的調(diào)用,實現(xiàn)了對接口Sourceable的實現(xiàn)類SourceSub1和SourceSub2的調(diào)用。接下來我再畫個圖,大家就應(yīng)該明白了,因為這個圖是我們JDBC連接的原理,有數(shù)據(jù)庫學(xué)習(xí)基礎(chǔ)的,一結(jié)合就都懂了。

    2

    11、組合模式(Composite)

    組合模式有時又叫部分-整體模式在處理類似樹形結(jié)構(gòu)的問題時比較方便,看看關(guān)系圖:

    直接來看代碼:

  • 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;??
  • ????}??
  • ??????
  • ????//添加孩子節(jié)點??
  • ????public?void?add(TreeNode?node){??
  • ????????children.add(node);??
  • ????}??
  • ??????
  • ????//刪除孩子節(jié)點??
  • ????public?void?remove(TreeNode?node){??
  • ????????children.remove(node);??
  • ????}??
  • ??????
  • ????//取得孩子節(jié)點??
  • ????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!”);??
  • ????}??
  • }??
  • 使用場景:將多個對象組合在一起進行操作,常用于表示樹形結(jié)構(gòu)中,例如二叉樹,數(shù)等。

    12、享元模式(Flyweight)

    享元模式的主要目的是實現(xiàn)對象的共享,即共享池,當(dāng)系統(tǒng)中對象多的時候可以減少內(nèi)存的開銷,通常與工廠模式一起使用。

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

    看個例子:

    看下數(shù)據(jù)庫連接池的代碼:

  • 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;??
  • ??
  • ????/*構(gòu)造方法,做一些初始化工作*/??
  • ????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);??
  • ????}??
  • ??
  • ????/*?返回連接池中的一個數(shù)據(jù)庫連接?*/??
  • ????public?synchronized?Connection?getConnection()?{??
  • ????????if?(pool.size()?>?0)?{??
  • ????????????Connection?conn?=?pool.get(0);??
  • ????????????pool.remove(conn);??
  • ????????????return?conn;??
  • ????????}?else?{??
  • ????????????return?null;??
  • ????????}??
  • ????}??
  • }??
  • 通過連接池的管理,實現(xiàn)了數(shù)據(jù)庫連接的共享,不需要每一次都重新創(chuàng)建連接,節(jié)省了數(shù)據(jù)庫重新創(chuàng)建的開銷,提升了系統(tǒng)的性能!本章講解了7種結(jié)構(gòu)型模式,因為篇幅的問題,剩下的11種行為型模式,

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

    先來張圖,看看這11中模式的關(guān)系:

    第一類:通過父類與子類的關(guān)系進行實現(xiàn)。第二類:兩個類之間。第三類:類的狀態(tài)。第四類:通過中間類

    13、策略模式(strategy)

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

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

    首先統(tǒng)一接口:

  • 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;??
  • ????}??
  • }??
  • 三個實現(xiàn)類:

  • 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

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

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

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

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

  • public?abstract?class?AbstractCalculator?{??
  • ??????
  • ????/*主方法,實現(xiàn)對本類其它方法的調(diào)用*/??
  • ????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);??
  • ????}??
  • }??
  • 我跟蹤下這個小程序的執(zhí)行過程:首先將exp和”\\+”做參數(shù),調(diào)用AbstractCalculator類里的 calculate(String,String)方法,在calculate(String,String)里調(diào)用同類的split(),之后再調(diào)用 calculate(int ,int)方法,從這個方法進入到子類中,執(zhí)行完return num1 + num2后,將值返回到AbstractCalculator類,賦給result,打印出來。正好驗證了我們開頭的思路。

    15、觀察者模式(Observer)

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

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

    一個Observer接口:

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

  • 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接口及實現(xiàn)類:

  • 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!

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

    16、迭代子模式(Iterator)

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

    ?

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

    兩個接口:

  • 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();??
  • }??
  • 兩個實現(xiàn):

  • 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中各個類也都是這些基本的東西,加一些設(shè)計模式,再加一些優(yōu)化放到一起的,只要我們把這些東西學(xué)會了,掌握好了,我們也可以寫出自己的集合類,甚至框架!

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

    ?

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

  • 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!

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

    ?18、命令模式(Command)

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

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

  • 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!

    這個很哈理解,命令模式的目的就是達到命令的發(fā)出者和執(zhí)行者之間解耦,實現(xiàn)請求和執(zhí)行分開,熟悉Struts的同學(xué)應(yīng)該知道,Struts其實就是一種將請求和呈現(xiàn)分離的技術(shù),其中必然涉及命令模式的思想!

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

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

    19、備忘錄模式(Memento)

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

    Original類是原始類,里面有需要保存的屬性value及創(chuàng)建一個備忘錄類,用來保存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)?{??
  • ??????????
  • ????????//?創(chuàng)建原始類??
  • ????????Original?origi?=?new?Original(“egg”);??
  • ??
  • ????????//?創(chuàng)建備忘錄??
  • ????????Storage?storage?=?new?Storage(origi.createMemento());??
  • ??
  • ????????//?修改原始類的狀態(tài)??
  • ????????System.out.println(“初始化狀態(tài)為:”?+?origi.getValue());??
  • ????????origi.setValue(“niu”);??
  • ????????System.out.println(“修改后的狀態(tài)為:”?+?origi.getValue());??
  • ??
  • ????????//?回復(fù)原始類的狀態(tài)??
  • ????????origi.restoreMemento(storage.getMemento());??
  • ????????System.out.println(“恢復(fù)后的狀態(tài)為:”?+?origi.getValue());??
  • ????}??
  • }??
  • 輸出:

    初始化狀態(tài)為:egg 修改后的狀態(tài)為:niu 恢復(fù)后的狀態(tài)為:egg

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

    20、狀態(tài)模式(State)

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

    State類是個狀態(tài)類,Context類可以實現(xiàn)切換,我們來看看代碼:

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

  • ??
  • /**?
  • ?*?狀態(tài)類的核心類?
  • ?*?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;??
  • ??
  • /**?
  • ?*?狀態(tài)模式的切換類???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);??
  • ??????????
  • ????????//設(shè)置第一種狀態(tài)??
  • ????????state.setValue(“state1″);??
  • ????????context.method();??
  • ??????????
  • ????????//設(shè)置第二種狀態(tài)??
  • ????????state.setValue(“state2″);??
  • ????????context.method();??
  • ????}??
  • }??
  • 輸出:

    execute the first opt! execute the second opt!

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

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

    簡單來說,訪問者模式就是一種分離對象數(shù)據(jù)結(jié)構(gòu)與行為的方法,通過這種分離,可達到為一個被訪問者動態(tài)添加新的操作而無需做其它的修改的效果。簡單關(guān)系圖:

    來看看原碼:一個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?“l(fā)ove”;??
  • ????}??
  • }??
  • 測試:

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

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

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

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

  • 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) 解釋器模式是我們暫時的最后一講,一般主要應(yīng)用在OOP開發(fā)中的編譯器的開發(fā)中,所以適用面比較窄。

    Context類是一個上下文環(huán)境類,Plus和Minus分別是用來計算的實現(xiàn),代碼如下:

  • 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);??
  • ????}??
  • }??
  • 最后輸出正確的結(jié)果:3。

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。