隨筆-11  評論-0  文章-0  trackbacks-0
            2015年7月21日
               摘要: 設計模式的六大原則總原則:開閉原則(Open Close Principle)開閉原則就是說對擴展開放,對修改關閉。在程序需要進行拓展的時候,不能去修改原有的代碼,而是要擴展原有代碼,實現一個熱插拔的效果。所以一句話概括就是:為了使程序的擴展性好,易于維護和升級。想要達到這樣的效果,我們需要使用接口和抽象類等,后面的具體設計中我們會提到這點。1、單一職責原則不要存在多于一個導致類變更的原因,也就是...  閱讀全文
          posted @ 2015-07-21 16:44 wxb1988 閱讀(213) | 評論 (0)編輯 收藏
            2015年7月20日
          定義:為創建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。

          類型:創建類模式

          類圖:

          抽象工廠模式與工廠方法模式的區別

                  抽象工廠模式是工廠方法模式的升級版本,他用來創建一組相關或者相互依賴的對象。他與工廠方法模式的區別就在于,工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則是針對的多個產品等級結構。在編程中,通常一個產品結構,表現為一個接口或者抽象類,也就是說,工廠方法模式提供的所有產品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不同的接口或抽象類。

                  在抽象工廠模式中,有一個產品族的概念:所謂的產品族,是指位于不同產品等級結構中功能相關聯的產品組成的家族。抽象工廠模式所提供的一系列產品就組成一個產品族;而工廠方法提供的一系列產品稱為一個等級結構。我們依然拿生產汽車的例子來說明他們之間的區別。

                  在上面的類圖中,兩廂車和三廂車稱為兩個不同的等級結構;而2.0排量車和2.4排量車則稱為兩個不同的產品族。再具體一點,2.0排量兩廂車和2.4排量兩廂車屬于同一個等級結構,2.0排量三廂車和2.4排量三廂車屬于另一個等級結構;而2.0排量兩廂車和2.0排量三廂車屬于同一個產品族,2.4排量兩廂車和2.4排量三廂車屬于另一個產品族。

                  明白了等級結構和產品族的概念,就理解工廠方法模式和抽象工廠模式的區別了,如果工廠的產品全部屬于同一個等級結構,則屬于工廠方法模式;如果工廠的產品來自多個等級結構,則屬于抽象工廠模式。在本例中,如果一個工廠模式提供2.0排量兩廂車和2.4排量兩廂車,那么他屬于工廠方法模式;如果一個工廠模式是提供2.4排量兩廂車和2.4排量三廂車兩個產品,那么這個工廠模式就是抽象工廠模式,因為他提供的產品是分屬兩個不同的等級結構。當然,如果一個工廠提供全部四種車型的產品,因為產品分屬兩個等級結構,他當然也屬于抽象工廠模式了。

          抽象工廠模式代碼

          1. interface IProduct1 {  
          2.     public void show();  
          3. }  
          4. interface IProduct2 {  
          5.     public void show();  
          6. }  
          7.   
          8. class Product1 implements IProduct1 {  
          9.     public void show() {  
          10.         System.out.println("這是1型產品");  
          11.     }  
          12. }  
          13. class Product2 implements IProduct2 {  
          14.     public void show() {  
          15.         System.out.println("這是2型產品");  
          16.     }  
          17. }  
          18.   
          19. interface IFactory {  
          20.     public IProduct1 createProduct1();  
          21.     public IProduct2 createProduct2();  
          22. }  
          23. class Factory implements IFactory{  
          24.     public IProduct1 createProduct1() {  
          25.         return new Product1();  
          26.     }  
          27.     public IProduct2 createProduct2() {  
          28.         return new Product2();  
          29.     }  
          30. }  
          31.   
          32. public class Client {  
          33.     public static void main(String[] args){  
          34.         IFactory factory = new Factory();  
          35.         factory.createProduct1().show();  
          36.         factory.createProduct2().show();  
          37.     }  
          38. }  

          抽象工廠模式的優點

                  抽象工廠模式除了具有工廠方法模式的優點外,最主要的優點就是可以在類的內部對產品族進行約束。所謂的產品族,一般或多或少的都存在一定的關聯,抽象工廠模式就可以在類內部對產品族的關聯關系進行定義和描述,而不必專門引入一個新的類來進行管理。

           

          抽象工廠模式的缺點

                 產品族的擴展將是一件十分費力的事情,假如產品族中需要增加一個新的產品,則幾乎所有的工廠類都需要進行修改。所以使用抽象工廠模式時,對產品等級結構的劃分是非常重要的。

           

          適用場景

                 當需要創建的對象是一系列相互關聯或相互依賴的產品族時,便可以使用抽象工廠模式。說的更明白一點,就是一個繼承體系中,如果存在著多個等級結構(即存在著多個抽象類),并且分屬各個等級結構中的實現類之間存在著一定的關聯或者約束,就可以使用抽象工廠模式。假如各個等級結構中的實現類之間不存在關聯或約束,則使用多個獨立的工廠來對產品進行創建,則更合適一點。

           

          總結

                 無論是簡單工廠模式,工廠方法模式,還是抽象工廠模式,他們都屬于工廠模式,在形式和特點上也是極為相似的,他們的最終目的都是為了解耦。在使用時,我們不必去在意這個模式到底工廠方法模式還是抽象工廠模式,因為他們之間的演變常常是令人琢磨不透的。經常你會發現,明明使用的工廠方法模式,當新需求來臨,稍加修改,加入了一個新方法后,由于類中的產品構成了不同等級結構中的產品族,它就變成抽象工廠模式了;而對于抽象工廠模式,當減少一個方法使的提供的產品不再構成產品族之后,它就演變成了工廠方法模式。

                 所以,在使用工廠模式時,只需要關心降低耦合度的目的是否達到了。

          posted @ 2015-07-20 22:34 wxb1988 閱讀(196) | 評論 (0)編輯 收藏

          定義:定義一個用于創建對象的接口,讓子類決定實例化哪一個類,工廠方法使一個類的實例化延遲到其子類。

          類型:創建類模式

          類圖:

          工廠方法模式代碼

          1. interface IProduct {  
          2.     public void productMethod();  
          3. }  
          4.   
          5. class Product implements IProduct {  
          6.     public void productMethod() {  
          7.         System.out.println("產品");  
          8.     }  
          9. }  
          10.   
          11. interface IFactory {  
          12.     public IProduct createProduct();  
          13. }  
          14.   
          15. class Factory implements IFactory {  
          16.     public IProduct createProduct() {  
          17.         return new Product();  
          18.     }  
          19. }  
          20.   
          21. public class Client {  
          22.     public static void main(String[] args) {  
          23.         IFactory factory = new Factory();  
          24.         IProduct prodect = factory.createProduct();  
          25.         prodect.productMethod();  
          26.     }  
          27. }  

          工廠模式:

                  首先需要說一下工廠模式。工廠模式根據抽象程度的不同分為三種:簡單工廠模式(也叫靜態工廠模式)、本文所講述的工廠方法模式、以及抽象工廠模式。工廠模式是編程中經常用到的一種模式。它的主要優點有:

          • 可以使代碼結構清晰,有效地封裝變化。在編程中,產品類的實例化有時候是比較復雜和多變的,通過工廠模式,將產品的實例化封裝起來,使得調用者根本無需關心產品的實例化過程,只需依賴工廠即可得到自己想要的產品。
          • 對調用者屏蔽具體的產品類。如果使用工廠模式,調用者只關心產品的接口就可以了,至于具體的實現,調用者根本無需關心。即使變更了具體的實現,對調用者來說沒有任何影響。
          • 降低耦合度。產品類的實例化通常來說是很復雜的,它需要依賴很多的類,而這些類對于調用者來說根本無需知道,如果使用了工廠方法,我們需要做的僅僅是實例化好產品類,然后交給調用者使用。對調用者來說,產品所依賴的類都是透明的。

           

          工廠方法模式:

                 通過工廠方法模式的類圖可以看到,工廠方法模式有四個要素:

          • 工廠接口。工廠接口是工廠方法模式的核心,與調用者直接交互用來提供產品。在實際編程中,有時候也會使用一個抽象類來作為與調用者交互的接口,其本質上是一樣的。
          • 工廠實現。在編程中,工廠實現決定如何實例化產品,是實現擴展的途徑,需要有多少種產品,就需要有多少個具體的工廠實現。
          • 產品接口。產品接口的主要目的是定義產品的規范,所有的產品實現都必須遵循產品接口定義的規范。產品接口是調用者最為關心的,產品接口定義的優劣直接決定了調用者代碼的穩定性。同樣,產品接口也可以用抽象類來代替,但要注意最好不要違反里氏替換原則。
          • 產品實現。實現產品接口的具體類,決定了產品在客戶端中的具體行為。

                  前文提到的簡單工廠模式跟工廠方法模式極為相似,區別是:簡單工廠只有三個要素,他沒有工廠接口,并且得到產品的方法一般是靜態的。因為沒有工廠接口,所以在工廠實現的擴展性方面稍弱,可以算所工廠方法模式的簡化版,關于簡單工廠模式,在此一筆帶過。

                

          適用場景:

                  不管是簡單工廠模式,工廠方法模式還是抽象工廠模式,他們具有類似的特性,所以他們的適用場景也是類似的。

                  首先,作為一種創建類模式,在任何需要生成復雜對象的地方,都可以使用工廠方法模式。有一點需要注意的地方就是復雜對象適合使用工廠模式,而簡單對象,特別是只需要通過new就可以完成創建的對象,無需使用工廠模式。如果使用工廠模式,就需要引入一個工廠類,會增加系統的復雜度。

                 其次,工廠模式是一種典型的解耦模式,迪米特法則在工廠模式中表現的尤為明顯。假如調用者自己組裝產品需要增加依賴關系時,可以考慮使用工廠模式。將會大大降低對象之間的耦合度。

                 再次,由于工廠模式是依靠抽象架構的,它把實例化產品的任務交由實現類完成,擴展性比較好。也就是說,當需要系統有比較好的擴展性時,可以考慮工廠模式,不同的產品用不同的實現工廠來組裝。

                

          典型應用

                 要說明工廠模式的優點,可能沒有比組裝汽車更合適的例子了。場景是這樣的:汽車由發動機、輪、底盤組成,現在需要組裝一輛車交給調用者。假如不使用工廠模式,代碼如下:

          1. class Engine {  
          2.     public void getStyle(){  
          3.         System.out.println("這是汽車的發動機");  
          4.     }  
          5. }  
          6. class Underpan {  
          7.     public void getStyle(){  
          8.         System.out.println("這是汽車的底盤");  
          9.     }  
          10. }  
          11. class Wheel {  
          12.     public void getStyle(){  
          13.         System.out.println("這是汽車的輪胎");  
          14.     }  
          15. }  
          16. public class Client {  
          17.     public static void main(String[] args) {  
          18.         Engine engine = new Engine();  
          19.         Underpan underpan = new Underpan();  
          20.         Wheel wheel = new Wheel();  
          21.         ICar car = new Car(underpan, wheel, engine);  
          22.         car.show();  
          23.     }  
          24. }  


                  可以看到,調用者為了組裝汽車還需要另外實例化發動機、底盤和輪胎,而這些汽車的組件是與調用者無關的,嚴重違反了迪米特法則,耦合度太高。并且非常不利于擴展。另外,本例中發動機、底盤和輪胎還是比較具體的,在實際應用中,可能這些產品的組件也都是抽象的,調用者根本不知道怎樣組裝產品。假如使用工廠方法的話,整個架構就顯得清晰了許多。

          1. interface IFactory {  
          2.     public ICar createCar();  
          3. }  
          4. class Factory implements IFactory {  
          5.     public ICar createCar() {  
          6.         Engine engine = new Engine();  
          7.         Underpan underpan = new Underpan();  
          8.         Wheel wheel = new Wheel();  
          9.         ICar car = new Car(underpan, wheel, engine);  
          10.         return car;  
          11.     }  
          12. }  
          13. public class Client {  
          14.     public static void main(String[] args) {  
          15.         IFactory factory = new Factory();  
          16.         ICar car = factory.createCar();  
          17.         car.show();  
          18.     }  
          19. }  

                  使用工廠方法后,調用端的耦合度大大降低了。并且對于工廠來說,是可以擴展的,以后如果想組裝其他的汽車,只需要再增加一個工廠類的實現就可以。無論是靈活性還是穩定性都得到了極大的提高。

          posted @ 2015-07-20 22:32 wxb1988 閱讀(208) | 評論 (0)編輯 收藏
          定義:確保一個類只有一個實例,而且自行實例化并向整個系統提供這個實例。

          類型:創建類模式

          類圖:

          類圖知識點:

          1.類圖分為三部分,依次是類名、屬性、方法

          2.以<<開頭和以>>結尾的為注釋信息

          3.修飾符+代表public,-代表private,#代表protected,什么都沒有代表包可見。

          4.帶下劃線的屬性或方法代表是靜態的。

          5.對類圖中對象的關系不熟悉的朋友可以參考文章:設計模式中類的關系

          單例模式應該是23種設計模式中最簡單的一種模式了。它有以下幾個要素:

          • 私有的構造方法
          • 指向自己實例的私有靜態引用
          • 以自己實例為返回值的靜態的公有的方法

                  單例模式根據實例化對象時機的不同分為兩種:一種是餓漢式單例,一種是懶漢式單例。餓漢式單例在單例類被加載時候,就實例化一個對象交給自己的引用;而懶漢式在調用取得實例方法的時候才會實例化對象。代碼如下:

          餓漢式單例

          1. public class Singleton {  
          2.     private static Singleton singleton = new Singleton();  
          3.     private Singleton(){}  
          4.     public static Singleton getInstance(){  
          5.         return singleton;  
          6.     }  
          7. }  

          懶漢式單例

          1. public class Singleton {  
          2.     private static Singleton singleton;  
          3.     private Singleton(){}  
          4.       
          5.     public static synchronized Singleton getInstance(){  
          6.         if(singleton==null){  
          7.             singleton = new Singleton();  
          8.         }  
          9.         return singleton;  
          10.     }  
          11. }  

          單例模式的優點:

          • 在內存中只有一個對象,節省內存空間。
          • 避免頻繁的創建銷毀對象,可以提高性能。
          • 避免對共享資源的多重占用。
          • 可以全局訪問。

          適用場景:由于單例模式的以上優點,所以是編程中用的比較多的一種設計模式。我總結了一下我所知道的適合使用單例模式的場景:

          • 需要頻繁實例化然后銷毀的對象。
          • 創建對象時耗時過多或者耗資源過多,但又經常用到的對象。
          • 有狀態的工具類對象。
          • 頻繁訪問數據庫或文件的對象。
          • 以及其他我沒用過的所有要求只有一個對象的場景。

          單例模式注意事項:

          • 只能使用單例類提供的方法得到單例對象,不要使用反射,否則將會實例化一個新對象。
          • 不要做斷開單例類對象與類中靜態引用的危險操作。
          • 多線程使用單例使用共享資源時,注意線程安全問題。

          關于java中單例模式的一些爭議:

          單例模式的對象長時間不用會被jvm垃圾收集器收集嗎

                  看到不少資料中說:如果一個單例對象在內存中長久不用,會被jvm認為是一個垃圾,在執行垃圾收集的時候會被清理掉。對此這個說法,筆者持懷疑態度,筆者本人的觀點是:在hotspot虛擬機1.6版本中,除非人為地斷開單例中靜態引用到單例對象的聯接,否則jvm垃圾收集器是不會回收單例對象的。

          對于這個爭議,筆者單獨寫了一篇文章進行討論,如果您有不同的觀點或者有過這方面的經歷請進入文章單例模式討論篇:單例模式與垃圾收集參與討論。

           

          在一個jvm中會出現多個單例嗎

                  在分布式系統、多個類加載器、以及序列化的的情況下,會產生多個單例,這一點是無庸置疑的。那么在同一個jvm中,會不會產生單例呢?使用單例提供的getInstance()方法只能得到同一個單例,除非是使用反射方式,將會得到新的單例。代碼如下

          1. Class c = Class.forName(Singleton.class.getName());  
          2. Constructor ct = c.getDeclaredConstructor();  
          3. ct.setAccessible(true);  
          4. Singleton singleton = (Singleton)ct.newInstance();  

          這樣,每次運行都會產生新的單例對象。所以運用單例模式時,一定注意不要使用反射產生新的單例對象。

           

          懶漢式單例線程安全嗎

                  主要是網上的一些說法,懶漢式的單例模式是線程不安全的,即使是在實例化對象的方法上加synchronized關鍵字,也依然是危險的,但是筆者經過編碼測試,發現加synchronized關鍵字修飾后,雖然對性能有部分影響,但是卻是線程安全的,并不會產生實例化多個對象的情況。

           

          單例模式只有餓漢式和懶漢式兩種嗎

                  餓漢式單例和懶漢式單例只是兩種比較主流和常用的單例模式方法,從理論上講,任何可以實現一個類只有一個實例的設計模式,都可以稱為單例模式。

           

          單例類可以被繼承嗎

                  餓漢式單例和懶漢式單例由于構造方法是private的,所以他們都是不可繼承的,但是其他很多單例模式是可以繼承的,例如登記式單例。

           

          餓漢式單例好還是懶漢式單例好

                  在java中,餓漢式單例要優于懶漢式單例。C++中則一般使用懶漢式單例。

          單例模式比較簡單,在此就不舉例代碼演示了。

          單例模式與垃圾回收

                 Jvm的垃圾回收機制到底會不會回收掉長時間不用的單例模式對象,這的確是一個比較有爭議性的問題。將這一部分內容單獨成篇的目的也是為了與廣大博友廣泛的討論一下這個問題。為了能讓更多的人看到這篇文章,請各位博友看完文章之后,點一下“頂”,讓本篇文章排名盡量的靠前。筆者在此謝過。


          討論命題:當一個單例的對象長久不用時,會不會被jvm的垃圾收集機制回收。

                  首先說一下為什么會產生這一疑問,筆者本人再此之前從來沒有考慮過垃圾回收對單例模式的影響,直到去年讀了一本書,《設計模式之禪》秦小波著。在書中提到在j2ee應用中,jvm垃圾回收機制會把長久不用的單例類對象當作垃圾,并在cpu空閑的時候對其進行回收。之前讀過的幾本設計模式的書,包括《java與模式》,書中都沒有提到jvm垃圾回收機制對單例的影響。并且在工作過程中,也沒有過單例對象被回收的經歷,加上工作中很多前輩曾經告誡過筆者:盡量不要聲明太多的靜態屬性,因為這些靜態屬性被加載后不會被釋放。因此對jvm垃圾收集會回收單例對象這一說法持懷疑態度。漸漸地,發現在同事中和網上的技術人員中,對這一問題也基本上是鮮明的對立兩派。那么到底jvm會不會回收長久不用的單例對象呢。

                  對這一問題,筆者本人的觀點是:不會回收。

          下面給出本人的測試代碼

          1. class Singleton {  
          2.     private byte[] a = new byte[6*1024*1024];  
          3.     private static Singleton singleton = new Singleton();  
          4.     private Singleton(){}  
          5.       
          6.     public static Singleton getInstance(){  
          7.         return singleton;  
          8.     }  
          9. }  
          10.   
          11. class Obj {  
          12.     private byte[] a = new byte[3*1024*1024];  
          13. }  
          14.   
          15. public class Client{  
          16.     public static void main(String[] args) throws Exception{  
          17.         Singleton.getInstance();  
          18.         while(true){  
          19.             new Obj();  
          20.         }  
          21.     }  
          22. }  

                  本段程序的目的是模擬j2ee容器,首先實例化單例類,這個單例類占6M內存,然后程序進入死循環,不斷的創建對象,逼迫jvm進行垃圾回收,然后觀察垃圾收集信息,如果進行垃圾收集后,內存仍然大于6M,則說明垃圾回收不會回收單例對象。

                  運行本程序使用的虛擬機是hotspot虛擬機,也就是我們使用的最多的java官方提供的虛擬機,俗稱jdk,版本是jdk1.6.0_12

                  運行時vm arguments參數為:-verbose:gc -Xms20M -Xmx20M,意思是每次jvm進行垃圾回收時顯示內存信息,jvm的內存設為固定20M。

          運行結果:

          ……

          [Full GC 18566K->6278K(20352K), 0.0101066 secs]

          [GC 18567K->18566K(20352K), 0.0001978 secs]

          [Full GC 18566K->6278K(20352K), 0.0088229 secs]

          ……

                  從運行結果中可以看到總有6M空間沒有被收集。因此,筆者認為,至少在hotspot虛擬機中,垃圾回收是不會回收單例對象的。

                  后來查閱了一些相關的資料,hotspot虛擬機的垃圾收集算法使用根搜索算法。這個算法的基本思路是:對任何“活”的對象,一定能最終追溯到其存活在堆棧或靜態存儲區之中的引用。通過一系列名為根(GC Roots)的引用作為起點,從這些根開始搜索,經過一系列的路徑,如果可以到達java堆中的對象,那么這個對象就是“活”的,是不可回收的。可以作為根的對象有:

          • 虛擬機棧(棧楨中的本地變量表)中的引用的對象。
          • 方法區中的類靜態屬性引用的對象。
          • 方法區中的常量引用的對象。
          • 本地方法棧中JNI的引用的對象。

                  方法區是jvm的一塊內存區域,用來存放類相關的信息。很明顯,java中單例模式創建的對象被自己類中的靜態屬性所引用,符合第二條,因此,單例對象不會被jvm垃圾收集。

                  雖然jvm堆中的單例對象不會被垃圾收集,但是單例類本身如果長時間不用會不會被收集呢?因為jvm對方法區也是有垃圾收集機制的。如果單例類被收集,那么堆中的對象就會失去到根的路徑,必然會被垃圾收集掉。對此,筆者查閱了hotspot虛擬機對方法區的垃圾收集方法,jvm卸載類的判定條件如下:

          • 該類所有的實例都已經被回收,也就是java堆中不存在該類的任何實例。
          • 加載該類的ClassLoader已經被回收。
          • 該類對應的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。

                  只有三個條件都滿足,jvm才會在垃圾收集的時候卸載類。顯然,單例的類不滿足條件一,因此單例類也不會被卸載。也就是說,只要單例類中的靜態引用指向jvm堆中的單例對象,那么單例類和單例對象都不會被垃圾收集,依據根搜索算法,對象是否會被垃圾收集與未被使用時間長短無關,僅僅在于這個對象是不是“活”的。假如一個對象長久未使用而被回收,那么收集算法應該是最近最長未使用算法,最近最長未使用算法一般用在操作系統的內外存交換中,如果用在虛擬機垃圾回收中,豈不是太不安全了?以上是筆者的觀點。

                  因此筆者的觀點是:在hotspot虛擬機1.6版本中,除非人為地斷開單例中靜態引用到單例對象的聯接,否則jvm垃圾收集器是不會回收單例對象的。

          posted @ 2015-07-20 22:30 wxb1988 閱讀(218) | 評論 (0)編輯 收藏
               摘要: 單例對象(Singleton)是一種常用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:1、某些類創建比較頻繁,對于一些大型的對象,這是一筆很大的系統開銷。2、省去了new操作符,降低了系統內存的使用頻率,減輕GC壓力。3、有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以創建多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同...  閱讀全文
          posted @ 2015-07-20 22:28 wxb1988 閱讀(177) | 評論 (0)編輯 收藏
               摘要: 8.1 女媧造人的故事      東漢《風俗通》記錄了一則神話故事:“開天辟辟,未有人民,女媧搏,黃土作人……”,講述的內容就是大家非常熟悉的女媧造人的故事。開天辟地之初,大地上并沒有生物,只有蒼茫大地,純粹而潔凈的自然環境,寂靜而又寂寞,于是女媧決定創造一個新物種(即人類)來增加世界的繁榮,怎么制造...  閱讀全文
          posted @ 2015-07-20 22:20 wxb1988 閱讀(175) | 評論 (0)編輯 收藏

          工廠方法模式(Factory Method)

          簡單工廠模式有一個問題就是,類的創建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到工廠方法模式,創建一個工廠接口和創建多個工廠實現類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼。

          請看例子:

          1. public interface Sender {  
          2.     public void Send();  
          3. }  

          兩個實現類:

          1. public class MailSender implements Sender {  
          2.     @Override  
          3.     public void Send() {  
          4.         System.out.println("this is mailsender!");  
          5.     }  
          6. }  
          1. public class SmsSender implements Sender {  
          2.   
          3.     @Override  
          4.     public void Send() {  
          5.         System.out.println("this is sms sender!");  
          6.     }  
          7. }  

          兩個工廠類:

          1. public class SendMailFactory implements Provider {  
          2.       
          3.     @Override  
          4.     public Sender produce(){  
          5.         return new MailSender();  
          6.     }  
          7. }  
          1. public class SendSmsFactory implements Provider{  
          2.   
          3.     @Override  
          4.     public Sender produce() {  
          5.         return new SmsSender();  
          6.     }  
          7. }  

          在提供一個接口:

          1. public interface Provider {  
          2.     public Sender produce();  
          3. }  

          測試類:

          1. public class Test {  
          2.   
          3.     public static void main(String[] args) {  
          4.         Provider provider = new SendMailFactory();  
          5.         Sender sender = provider.produce();  
          6.         sender.Send();  
          7.     }  
          8. }  

          其實這個模式的好處就是,如果你現在想增加一個功能:發及時信息,則只需做一個實現類,實現Sender接口,同時做一個工廠類,實現Provider接口,就OK了,無需去改動現成的代碼。這樣做,拓展性較好!



          2、抽象工廠模式

          工廠方法模式和抽象工廠模式不好分清楚,他們的區別如下:

          工廠方法模式: 一個抽象產品類,可以派生出多個具體產品類。    一個抽象工廠類,可以派生出多個具體工廠類。    每個具體工廠類只能創建一個具體產品類的實例。  抽象工廠模式: 多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。    一個抽象工廠類,可以派生出多個具體工廠類。    每個具體工廠類可以創建多個具體產品類的實例,也就是創建的是一個產品線下的多個產品。         區別: 工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。    工廠方法模式的具體工廠類只能創建一個具體產品類的實例,而抽象工廠模式可以創建多個。
          工廠方法創建 "一種" 產品,他的著重點在于"怎么創建",也就是說如果你開發,你的大量代碼很可能圍繞著這種產品的構造,初始化這些細節上面。也因為如此,類似的產品之間有很多可以復用的特征,所以會和模版方法相隨。 

          抽象工廠需要創建一些列產品,著重點在于"創建哪些"產品上,也就是說,如果你開發,你的主要任務是劃分不同差異的產品線,并且盡量保持每條產品線接口一致,從而可以從同一個抽象工廠繼承。

          對于java來說,你能見到的大部分抽象工廠模式都是這樣的: ---它的里面是一堆工廠方法,每個工廠方法返回某種類型的對象。  比如說工廠可以生產鼠標和鍵盤。那么抽象工廠的實現類(它的某個具體子類)的對象都可以生產鼠標和鍵盤,但可能工廠A生產的是羅技的鍵盤和鼠標,工廠B是微軟的。  這樣A和B就是工廠,對應于抽象工廠; 每個工廠生產的鼠標和鍵盤就是產品,對應于工廠方法;  用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從羅技換到微軟。但是用了抽象工廠模式,你只要換家工廠,就可以同時替換鼠標和鍵盤一套。如果你要的產品有幾十個,當然用抽象工廠模式一次替換全部最方便(這個工廠會替你用相應的工廠方法)  所以說抽象工廠就像工廠,而工廠方法則像是工廠的一種產品生產線
          posted @ 2015-07-20 22:20 wxb1988 閱讀(165) | 評論 (0)編輯 收藏

          簡單工廠模式

          簡單工廠模式模式分為三種:

          01、普通

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

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

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

          1. public interface Sender {  
          2.     public void Send();  
          3. }  

          其次,創建實現類:

          1. public class MailSender implements Sender {  
          2.     @Override  
          3.     public void Send() {  
          4.         System.out.println("this is mailsender!");  
          5.     }  
          6. }  
          1. public class SmsSender implements Sender {  
          2.   
          3.     @Override  
          4.     public void Send() {  
          5.         System.out.println("this is sms sender!");  
          6.     }  
          7. }  

          最后,建工廠類:

          1. public class SendFactory {  
          2.   
          3.     public Sender produce(String type) {  
          4.         if ("mail".equals(type)) {  
          5.             return new MailSender();  
          6.         } else if ("sms".equals(type)) {  
          7.             return new SmsSender();  
          8.         } else {  
          9.             System.out.println("請輸入正確的類型!");  
          10.             return null;  
          11.         }  
          12.     }  
          13. }  

          我們來測試下:

          1. public class FactoryTest {  
          2.   
          3.     public static void main(String[] args) {  
          4.         SendFactory factory = new SendFactory();  
          5.         Sender sender = factory.produce("sms");  
          6.         sender.Send();  
          7.     }  
          8. }  

          輸出:this is sms sender!

          02、多個方法

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

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

          [java] view plaincopypublic class SendFactory {  
             public Sender produceMail(){  
          1.         return new MailSender();  
          2.     }  
          3.       
          4.     public Sender produceSms(){  
          5.         return new SmsSender();  
          6.     }  
          7. }  

          測試類如下:

          1. public class FactoryTest {  
          2.   
          3.     public static void main(String[] args) {  
          4.         SendFactory factory = new SendFactory();  
          5.         Sender sender = factory.produceMail();  
          6.         sender.Send();  
          7.     }  
          8. }  

          輸出:this is mailsender!

          03、多個靜態方法

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

          1. public class SendFactory {  
          2.       
          3.     public static Sender produceMail(){  
          4.         return new MailSender();  
          5.     }  
          6.       
          7.     public static Sender produceSms(){  
          8.         return new SmsSender();  
          9.     }  
          10. }  
          1. public class FactoryTest {  
          2.   
          3.     public static void main(String[] args) {      
          4.         Sender sender = SendFactory.produceMail();  
          5.         sender.Send();  
          6.     }  
          7. }  

          輸出:this is mailsender!

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

          posted @ 2015-07-20 22:05 wxb1988 閱讀(174) | 評論 (0)編輯 收藏

          簡單工廠模式解釋: 

                 簡單工廠模式(Simple Factory Pattern)屬于類的創新型模式,又叫靜態工廠方法模式(Static FactoryMethod Pattern),是通過專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。

          簡單工廠模式的UML圖: 

                 簡單工廠模式中包含的角色及其相應的職責如下:

                 工廠角色(Creator):這是簡單工廠模式的核心,由它負責創建所有的類的內部邏輯。當然工廠類必須能夠被外界調用,創建所需要的產品對象。

                 抽象(Product)產品角色:簡單工廠模式所創建的所有對象的父類,注意,這里的父類可以是接口也可以是抽象類,它負責描述所有實例所共有的公共接口。

                 具體產品(Concrete Product)角色:簡單工廠所創建的具體實例對象,這些具體的產品往往都擁有共同的父類。

          簡單工廠模式深入分析

                 簡單工廠模式解決的問題是如何去實例化一個合適的對象。

                 簡單工廠模式的核心思想就是:有一個專門的類來負責創建實例的過程。

                 具體來說,把產品看著是一系列的類的集合,這些類是由某個抽象類或者接口派生出來的一個對象樹。而工廠類用來產生一個合適的對象來滿足客戶的要求。

                 如果簡單工廠模式所涉及到的具體產品之間沒有共同的邏輯,那么我們就可以使用接口來扮演抽象產品的角色;如果具體產品之間有功能的邏輯或,我們就必須把這些共同的東西提取出來,放在一個抽象類中,然后讓具體產品繼承抽象類。為實現更好復用的目的,共同的東西總是應該抽象出來的。

                 在實際的的使用中,抽閑產品和具體產品之間往往是多層次的產品結構,如下圖所示:

          簡單工廠模式使用場景分析及代碼實現: 

                 GG請自己的女朋友和眾多美女吃飯,但是GG自己是不會做飯的或者做的飯很不好,這說明GG不用自己去創建各種食物的對象;各個美女都有各自的愛好,到麥當勞后她們喜歡吃什么直接去點就行了,麥當勞就是生產各種食物的工廠,這時候GG不用自己動手,也可以請這么多美女吃飯,所要做的就是買單O(∩_∩)O哈哈~,其UML圖如下所示:

                 實現代碼如下:

                 新建立一個食物的接口:

          package com.diermeng.designPattern.SimpleFactory;

           

          /*

           * 產品的抽象接口

           */

          public interface Food {

              /*

               * 獲得相應的食物

               */

              public void get();

          }

          接下來建立具體的產品:麥香雞和薯條

          package com.diermeng.designPattern.SimpleFactory.impl;

          import com.diermeng.designPattern.SimpleFactory.Food;

           

          /*

           * 麥香雞對抽象產品接口的實現

           */

          public class McChicken implements Food{

              /*

               * 獲取一份麥香雞

               */

              public void get(){

                  System.out.println("我要一份麥香雞");

              }

          }

          package com.diermeng.designPattern.SimpleFactory.impl;

          import com.diermeng.designPattern.SimpleFactory.Food;

           

          /*

           * 薯條對抽象產品接口的實現

           */

          public class Chips implements Food{

              /*

               * 獲取一份薯條

               */

              public void get(){

                  System.out.println("我要一份薯條");

              }

          }

          現在建立一個食物加工工廠:

          package com.diermeng.designPattern.SimpleFactory.impl;

          import com.diermeng.designPattern.SimpleFactory.Food;

           

           

          public class FoodFactory {

           

              public static Food getFood(String type) throws InstantiationException, IllegalAccessException, ClassNotFoundException {

                  if(type.equalsIgnoreCase("mcchicken")) {

                      return McChicken.class.newInstance();

           

                  } else if(type.equalsIgnoreCase("chips")) {

                      return Chips.class.newInstance();

                  } else {

                      System.out.println("哎呀!找不到相應的實例化類啦!");

                      return null;

                  }

           

           

              }

          }

          最后我們建立測試客戶端:

          package com.diermeng.designPattern.SimpleFactory.client;

          import com.diermeng.designPattern.SimpleFactory.Food;

          import com.diermeng.designPattern.SimpleFactory.impl.FoodFactory;

           

          /*

           * 測試客戶端

           */

          public class SimpleFactoryTest {

              public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {

           

                  //實例化各種食物

                  Food mcChicken = FoodFactory.getFood("McChicken");

                  Food chips = FoodFactory.getFood("Chips");

                  Food eggs = FoodFactory.getFood("Eggs");

           

                  //獲取食物

                  if(mcChicken!=null){

                      mcChicken.get();

                  }

                  if(chips!=null){

                      chips.get();

                  }

                  if(eggs!=null){

                      eggs.get();

                  }

           

           

              }

          }

          輸出的結果如下:

          哎呀!找不到相應的實例化類啦!

          我要一份麥香雞

          我要一份薯條

          簡單工廠模式的優缺點分析: 

                 優點:工廠類是整個模式的關鍵所在。它包含必要的判斷邏輯,能夠根據外界給定的信息,決定究竟應該創建哪個具體類的對象。用戶在使用時可以直接根據工廠類去創建所需的實例,而無需了解這些對象是如何創建以及如何組織的。有利于整個軟件體系結構的優化。

                缺點:由于工廠類集中了所有實例的創建邏輯,這就直接導致一旦這個工廠出了問題,所有的客戶端都會受到牽連;而且由于簡單工廠模式的產品室基于一個共同的抽象類或者接口,這樣一來,但產品的種類增加的時候,即有不同的產品接口或者抽象類的時候,工廠類就需要判斷何時創建何種種類的產品,這就和創建何種種類產品的產品相互混淆在了一起,違背了單一職責,導致系統喪失靈活性和可維護性。而且更重要的是,簡單工廠模式違背了“開放封閉原則”,就是違背了“系統對擴展開放,對修改關閉”的原則,因為當我新增加一個產品的時候必須修改工廠類,相應的工廠類就需要重新編譯一遍。

                總結一下:簡單工廠模式分離產品的創建者和消費者,有利于軟件系統結構的優化;但是由于一切邏輯都集中在一個工廠類中,導致了沒有很高的內聚性,同時也違背了“開放封閉原則”。另外,簡單工廠模式的方法一般都是靜態的,而靜態工廠方法是無法讓子類繼承的,因此,簡單工廠模式無法形成基于基類的繼承樹結構。

          簡單工廠模式的實際應用簡介: 

                 作為一個最基本和最簡單的設計模式,簡單工廠模式卻有很非常廣泛的應用,我們這里以Java中的JDBC操作數據庫為例來說明。

                  JDBC是SUN公司提供的一套數據庫編程接口API,它利用Java語言提供簡單、一致的方式來訪問各種關系型數據庫。Java程序通過JDBC可以執行SQL語句,對獲取的數據進行處理,并將變化了的數據存回數據庫,因此,JDBC是Java應用程序與各種關系數據進行對話的一種機制。用JDBC進行數據庫訪問時,要使用數據庫廠商提供的驅動程序接口與數據庫管理系統進行數據交互。

          客戶端要使用使用數據時,只需要和工廠進行交互即可,這就導致操作步驟得到極大的簡化,操作步驟按照順序依次為:注冊并加載數據庫驅動,一般使用Class.forName();創建與數據庫的鏈接Connection對象;創建SQL語句對象preparedStatement(sql);提交SQL語句,根據實際情況使用executeQuery()或者executeUpdate();顯示相應的結果;關閉數據庫。

          posted @ 2015-07-20 21:58 wxb1988 閱讀(189) | 評論 (0)編輯 收藏
            2015年7月19日

           在UML類圖中,常見的有以下幾種關系: 泛化(Generalization),  實現(Realization),關聯(Association),聚合(Aggregation),組合(Composition),依賴(Dependency)

                   1. 泛化(Generalization

                  【泛化關系】:是一種繼承關系,表示一般與特殊的關系,它指定了子類如何特化父類的所有特征和行為。例如:老虎是動物的一種,即有老虎的特性也有動物的共性。

                  【箭頭指向】:帶三角箭頭的實線,箭頭指向父類

          UML類圖幾種關系的總結 

                  2. 實現(Realization

                  【實現關系】:是一種類與接口的關系,表示類是接口所有特征和行為的實現.

                  【箭頭指向】:帶三角箭頭的虛線,箭頭指向接口

          UML類圖幾種關系的總結 

                  3. 關聯(Association)

                  【關聯關系】:是一種擁有的關系,它使一個類知道另一個類的屬性和方法;如:老師與學生,丈夫與妻子關聯可以是雙向的,也可以是單向的。雙向的關聯可以有兩個箭頭或者沒有箭頭,單向的關聯有一個箭頭。

                  【代碼體現】:成員變量

                  【箭頭及指向】:帶普通箭頭的實心線,指向被擁有者

          UML類圖幾種關系的總結 

                  上圖中,老師與學生是雙向關聯,老師有多名學生,學生也可能有多名老師。但學生與某課程間的關系為單向關聯,一名學生可能要上多門課程,課程是個抽象的東西他不擁有學生。 

                  下圖為自身關聯: 

          UML類圖幾種關系的總結

                  4. 聚合(Aggregation

                  【聚合關系】:是整體與部分的關系,且部分可以離開整體而單獨存在。如車和輪胎是整體和部分的關系,輪胎離開車仍然可以存在。

                  聚合關系是關聯關系的一種,是強的關聯關系;關聯和聚合在語法上無法區分,必須考察具體的邏輯關系。

                  【代碼體現】:成員變量

                  【箭頭及指向】:帶空心菱形的實心線,菱形指向整體

          UML類圖幾種關系的總結 

                  5. 組合(Composition)

                  【組合關系】:是整體與部分的關系,但部分不能離開整體而單獨存在。如公司和部門是整體和部分的關系,沒有公司就不存在部門。

                 組合關系是關聯關系的一種,是比聚合關系還要強的關系,它要求普通的聚合關系中代表整體的對象負責代表部分的對象的生命周期。

          【代碼體現】:成員變量

          【箭頭及指向】:帶實心菱形的實線,菱形指向整體

          UML類圖幾種關系的總結

                  6. 依賴(Dependency)

                  【依賴關系】:是一種使用的關系,即一個類的實現需要另一個類的協助,所以要盡量不使用雙向的互相依賴.

                  【代碼表現】:局部變量、方法的參數或者對靜態方法的調用

                  【箭頭及指向】:帶箭頭的虛線,指向被使用者

          UML類圖幾種關系的總結 

                  各種關系的強弱順序:

                  泛化 = 實現 > 組合 > 聚合 > 關聯 > 依賴 

                  下面這張UML圖,比較形象地展示了各種類圖關系:

          UML類圖幾種關系的總結

          posted @ 2015-07-19 22:39 wxb1988 閱讀(157) | 評論 (0)編輯 收藏
          僅列出標題  下一頁
          主站蜘蛛池模板: 阿坝| 开化县| 庆城县| 宁河县| 明光市| 平阳县| 平南县| 深泽县| 怀来县| 濮阳县| SHOW| 桂阳县| 凤山县| 西乡县| 施甸县| 大洼县| 盘锦市| 繁昌县| 从化市| 渑池县| 仙居县| 抚远县| 东乌| 邛崃市| 宁津县| 壶关县| 舟曲县| 宣汉县| 和顺县| 永州市| 房山区| 余干县| 赞皇县| 永定县| 小金县| 芒康县| 陵川县| 通山县| 尼玛县| 米脂县| 洱源县|