Java Design Pattern

1.工廠模式

工廠模式(Factory Pattern)是 Java 中最經常使用的設計模式之一。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。html

在工廠模式中,咱們在建立對象時不會對客戶端暴露建立邏輯,而且是經過使用一個共同的接口來指向新建立的對象。java

介紹

意圖:定義一個建立對象的接口,讓其子類本身決定實例化哪個工廠類,工廠模式使其建立過程延遲到子類進行。spring

主要解決:主要解決接口選擇的問題。數據庫

什麼時候使用:咱們明確地計劃不一樣條件下建立不一樣實例時。設計模式

如何解決:讓其子類實現工廠接口,返回的也是一個抽象的產品。緩存

關鍵代碼:建立過程在其子類執行。安全

應用實例: 一、您須要一輛汽車,能夠直接從工廠裏面提貨,而不用去管這輛汽車是怎麼作出來的,以及這個汽車裏面的具體實現。 二、Hibernate 換數據庫只需換方言和驅動就能夠。服務器

優勢: 一、一個調用者想建立一個對象,只要知道其名稱就能夠了。 二、擴展性高,若是想增長一個產品,只要擴展一個工廠類就能夠。 三、屏蔽產品的具體實現,調用者只關心產品的接口。多線程

缺點:每次增長一個產品時,都須要增長一個具體類和對象實現工廠,使得系統中類的個數成倍增長,在必定程度上增長了系統的複雜度,同時也增長了系統具體類的依賴。這並非什麼好事。框架

使用場景: 一、日誌記錄器:記錄可能記錄到本地硬盤、系統事件、遠程服務器等,用戶能夠選擇記錄日誌到什麼地方。 二、數據庫訪問,當用戶不知道最後系統採用哪一類數據庫,以及數據庫可能有變化時。 三、設計一個鏈接服務器的框架,須要三個協議,"POP3"、"IMAP"、"HTTP",能夠把這三個做爲產品類,共同實現一個接口。

注意事項:做爲一種建立類模式,在任何須要生成複雜對象的地方,均可以使用工廠方法模式。有一點須要注意的地方就是複雜對象適合使用工廠模式,而簡單對象,特別是只須要經過 new 就能夠完成建立的對象,無需使用工廠模式。若是使用工廠模式,就須要引入一個工廠類,會增長系統的複雜度。

 

實現

咱們將建立一個 Shape 接口和實現 Shape 接口的實體類。下一步是定義工廠類 ShapeFactory

FactoryPatternDemo,咱們的演示類使用 ShapeFactory 來獲取 Shape 對象。它將向 ShapeFactory 傳遞信息(CIRCLE / RECTANGLE / SQUARE),以便獲取它所需對象的類型。

工廠模式的 UML 圖

步驟 1

建立一個接口:

Shape.java

public interface Shape { void draw(); }

步驟 2

建立實現接口的實體類。

Rectangle.java

public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }

Square.java

public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } }

Circle.java

public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }

步驟 3

建立一個工廠,生成基於給定信息的實體類的對象。

ShapeFactory.java

public class ShapeFactory { //使用 getShape 方法獲取形狀類型的對象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } }

步驟 4

使用該工廠,經過傳遞類型信息來獲取實體類的對象。

FactoryPatternDemo.java

public class FactoryPatternDemo { public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); //獲取 Circle 的對象,並調用它的 draw 方法 Shape shape1 = shapeFactory.getShape("CIRCLE"); //調用 Circle 的 draw 方法 shape1.draw(); //獲取 Rectangle 的對象,並調用它的 draw 方法 Shape shape2 = shapeFactory.getShape("RECTANGLE"); //調用 Rectangle 的 draw 方法 shape2.draw(); //獲取 Square 的對象,並調用它的 draw 方法 Shape shape3 = shapeFactory.getShape("SQUARE"); //調用 Square 的 draw 方法 shape3.draw(); } }

步驟 5

執行程序,輸出結果:

Inside Circle::draw() method. Inside Rectangle::draw() method. Inside Square::draw() method.

 

 

 

 

 

 

2.單例模式

單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。

這種模式涉及到一個單一的類,該類負責建立本身的對象,同時確保只有單個對象被建立。這個類提供了一種訪問其惟一的對象的方式,能夠直接訪問,不須要實例化該類的對象。

注意:

  • 一、單例類只能有一個實例。
  • 二、單例類必須本身建立本身的惟一實例。
  • 三、單例類必須給全部其餘對象提供這一實例。

 

介紹

意圖:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

主要解決:一個全局使用的類頻繁地建立與銷燬。

什麼時候使用:當您想控制實例數目,節省系統資源的時候。

如何解決:判斷系統是否已經有這個單例,若是有則返回,若是沒有則建立。

關鍵代碼:構造函數是私有的。

應用實例:

  • 一、一個班級只有一個班主任。
  • 二、Windows 是多進程多線程的,在操做一個文件的時候,就不可避免地出現多個進程或線程同時操做一個文件的現象,因此全部文件的處理必須經過惟一的實例來進行。
  • 三、一些設備管理器經常設計爲單例模式,好比一個電腦有兩臺打印機,在輸出的時候就要處理不能兩臺打印機打印同一個文件。

優勢:

  • 一、在內存裏只有一個實例,減小了內存的開銷,尤爲是頻繁的建立和銷燬實例(好比管理學院首頁頁面緩存)。
  • 二、避免對資源的多重佔用(好比寫文件操做)。

缺點:沒有接口,不能繼承,與單一職責原則衝突,一個類應該只關心內部邏輯,而不關心外面怎麼樣來實例化。

使用場景:

  • 一、要求生產惟一序列號。
  • 二、WEB 中的計數器,不用每次刷新都在數據庫里加一次,用單例先緩存起來。
  • 三、建立的一個對象須要消耗的資源過多,好比 I/O 與數據庫的鏈接等。

注意事項:getInstance() 方法中須要使用同步鎖 synchronized (Singleton.class) 防止多線程同時進入形成 instance 被屢次實例化。

 

實現

咱們將建立一個 SingleObject 類。SingleObject 類有它的私有構造函數和自己的一個靜態實例。

SingleObject 類提供了一個靜態方法,供外界獲取它的靜態實例。SingletonPatternDemo,咱們的演示類使用 SingleObject 類來獲取 SingleObject對象。

單例模式的 UML 圖

步驟 1

建立一個 Singleton 類。

SingleObject.java

public class SingleObject { //建立 SingleObject 的一個對象 private static SingleObject instance = new SingleObject(); //讓構造函數爲 private,這樣該類就不會被實例化 private SingleObject(){} //獲取惟一可用的對象 public static SingleObject getInstance(){ return instance; } public void showMessage(){ System.out.println("Hello World!"); } }

步驟 2

從 singleton 類獲取惟一的對象。

SingletonPatternDemo.java

public class SingletonPatternDemo { public static void main(String[] args) { //不合法的構造函數 //編譯時錯誤:構造函數 SingleObject() 是不可見的 //SingleObject object = new SingleObject(); //獲取惟一可用的對象 SingleObject object = SingleObject.getInstance(); //顯示消息 object.showMessage(); } }

步驟 3

執行程序,輸出結果:

Hello World!

 

 

 

 

 

 

3.原型模式

原型模式(Prototype Pattern)是用於建立重複的對象,同時又能保證性能。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。

這種模式是實現了一個原型接口,該接口用於建立當前對象的克隆。當直接建立對象的代價比較大時,則採用這種模式。例如,一個對象須要在一個高代價的數據庫操做以後被建立。咱們能夠緩存該對象,在下一個請求時返回它的克隆,在須要的時候更新數據庫,以此來減小數據庫調用。

介紹

意圖:用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。

主要解決:在運行期創建和刪除原型。

什麼時候使用: 一、當一個系統應該獨立於它的產品建立,構成和表示時。 二、當要實例化的類是在運行時刻指定時,例如,經過動態裝載。 三、爲了不建立一個與產品類層次平行的工廠類層次時。 四、當一個類的實例只能有幾個不一樣狀態組合中的一種時。創建相應數目的原型並克隆它們可能比每次用合適的狀態手工實例化該類更方便一些。

如何解決:利用已有的一個原型對象,快速地生成和原型對象同樣的實例。

關鍵代碼: 一、實現克隆操做,在 JAVA 繼承 Cloneable,重寫 clone(),在 .NET 中可使用 Object 類的 MemberwiseClone() 方法來實現對象的淺拷貝或經過序列化的方式來實現深拷貝。 二、原型模式一樣用於隔離類對象的使用者和具體類型(易變類)之間的耦合關係,它一樣要求這些"易變類"擁有穩定的接口。

應用實例: 一、細胞分裂。 二、JAVA 中的 Object clone() 方法。

優勢: 一、性能提升。 二、逃避構造函數的約束。

缺點: 一、配備克隆方法須要對類的功能進行通盤考慮,這對於全新的類不是很難,但對於已有的類不必定很容易,特別當一個類引用不支持串行化的間接對象,或者引用含有循環結構的時候。 二、必須實現 Cloneable 接口。

使用場景: 一、資源優化場景。 二、類初始化須要消化很是多的資源,這個資源包括數據、硬件資源等。 三、性能和安全要求的場景。 四、經過 new 產生一個對象須要很是繁瑣的數據準備或訪問權限,則可使用原型模式。 五、一個對象多個修改者的場景。 六、一個對象須要提供給其餘對象訪問,並且各個調用者可能都須要修改其值時,能夠考慮使用原型模式拷貝多個對象供調用者使用。 七、在實際項目中,原型模式不多單獨出現,通常是和工廠方法模式一塊兒出現,經過 clone 的方法建立一個對象,而後由工廠方法提供給調用者。原型模式已經與 Java 融爲渾然一體,你們能夠隨手拿來使用。

注意事項:與經過對一個類進行實例化來構造新對象不一樣的是,原型模式是經過拷貝一個現有對象生成新對象的。淺拷貝實現 Cloneable,重寫,深拷貝是經過實現 Serializable 讀取二進制流。

 

實現

咱們將建立一個抽象類 Shape 和擴展了 Shape 類的實體類。下一步是定義類 ShapeCache,該類把 shape 對象存儲在一個 Hashtable 中,並在請求的時候返回它們的克隆。

PrototypePatternDemo,咱們的演示類使用 ShapeCache 類來獲取 Shape 對象。

原型模式的 UML 圖

步驟 1

建立一個實現了 Cloneable 接口的抽象類。

Shape.java

public abstract class Shape implements Cloneable { private String id; protected String type; abstract void draw(); public String getType(){ return type; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Object clone() { Object clone = null; try { clone = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }

步驟 2

建立擴展了上面抽象類的實體類。

Rectangle.java

public class Rectangle extends Shape { public Rectangle(){ type = "Rectangle"; } @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } }

Square.java

public class Square extends Shape { public Square(){ type = "Square"; } @Override public void draw() { System.out.println("Inside Square::draw() method."); } }

Circle.java

public class Circle extends Shape { public Circle(){ type = "Circle"; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); } }

步驟 3

建立一個類,從數據庫獲取實體類,並把它們存儲在一個 Hashtable 中。

ShapeCache.java

import java.util.Hashtable; public class ShapeCache { private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>(); public static Shape getShape(String shapeId) { Shape cachedShape = shapeMap.get(shapeId); return (Shape) cachedShape.clone(); } // 對每種形狀都運行數據庫查詢,並建立該形狀 // shapeMap.put(shapeKey, shape); // 例如,咱們要添加三種形狀 public static void loadCache() { Circle circle = new Circle(); circle.setId("1"); shapeMap.put(circle.getId(),circle); Square square = new Square(); square.setId("2"); shapeMap.put(square.getId(),square); Rectangle rectangle = new Rectangle(); rectangle.setId("3"); shapeMap.put(rectangle.getId(),rectangle); } }

步驟 4

PrototypePatternDemo 使用 ShapeCache 類來獲取存儲在 Hashtable 中的形狀的克隆。

PrototypePatternDemo.java

public class PrototypePatternDemo { public static void main(String[] args) { ShapeCache.loadCache(); Shape clonedShape = (Shape) ShapeCache.getShape("1"); System.out.println("Shape : " + clonedShape.getType()); Shape clonedShape2 = (Shape) ShapeCache.getShape("2"); System.out.println("Shape : " + clonedShape2.getType()); Shape clonedShape3 = (Shape) ShapeCache.getShape("3"); System.out.println("Shape : " + clonedShape3.getType()); } }

步驟 5

執行程序,輸出結果:

Shape : Circle Shape : Square Shape : Rectangle

 

 

 

4.代理模式

在代理模式(Proxy Pattern)中,一個類表明另外一個類的功能。這種類型的設計模式屬於結構型模式。

在代理模式中,咱們建立具備現有對象的對象,以便向外界提供功能接口。

介紹

意圖:爲其餘對象提供一種代理以控制對這個對象的訪問。

主要解決:在直接訪問對象時帶來的問題,好比說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象因爲某些緣由(好比對象建立開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問),直接訪問會給使用者或者系統結構帶來不少麻煩,咱們能夠在訪問此對象時加上一個對此對象的訪問層。

什麼時候使用:想在訪問一個類時作一些控制。

如何解決:增長中間層。

關鍵代碼:實現與被代理類組合。

應用實例: 一、Windows 裏面的快捷方式。 二、豬八戒去找高翠蘭結果是孫悟空變的,能夠這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現了這個接口,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,因此說孫悟空是高翠蘭代理類。 三、買火車票不必定在火車站買,也能夠去代售點。 四、一張支票或銀行存單是帳戶中資金的代理。支票在市場交易中用來代替現金,並提供對簽發人帳號上資金的控制。 五、spring aop。

優勢: 一、職責清晰。 二、高擴展性。 三、智能化。

缺點: 一、因爲在客戶端和真實主題之間增長了代理對象,所以有些類型的代理模式可能會形成請求的處理速度變慢。 二、實現代理模式須要額外的工做,有些代理模式的實現很是複雜。

使用場景:按職責來劃分,一般有如下使用場景: 一、遠程代理。 二、虛擬代理。 三、Copy-on-Write 代理。 四、保護(Protect or Access)代理。 五、Cache代理。 六、防火牆(Firewall)代理。 七、同步化(Synchronization)代理。 八、智能引用(Smart Reference)代理。

注意事項: 一、和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口。 二、和裝飾器模式的區別:裝飾器模式爲了加強功能,而代理模式是爲了加以控制。

 

 

實現

咱們將建立一個 Image 接口和實現了 Image 接口的實體類。ProxyImage 是一個代理類,減小 RealImage 對象加載的內存佔用。

ProxyPatternDemo,咱們的演示類使用 ProxyImage 來獲取要加載的 Image 對象,並按照需求進行顯示。

代理模式的 UML 圖

步驟 1

建立一個接口。

Image.java

public interface Image { void display(); }

步驟 2

建立實現接口的實體類。

RealImage.java

public class RealImage implements Image { private String fileName; public RealImage(String fileName){ this.fileName = fileName; loadFromDisk(fileName); } @Override public void display() { System.out.println("Displaying " + fileName); } private void loadFromDisk(String fileName){ System.out.println("Loading " + fileName); } }

ProxyImage.java

public class ProxyImage implements Image{ private RealImage realImage; private String fileName; public ProxyImage(String fileName){ this.fileName = fileName; } @Override public void display() { if(realImage == null){ realImage = new RealImage(fileName); } realImage.display(); } }

步驟 3

當被請求時,使用 ProxyImage 來獲取 RealImage 類的對象。

ProxyPatternDemo.java

public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_10mb.jpg"); // 圖像將從磁盤加載 image.display(); System.out.println(""); // 圖像不須要從磁盤加載 image.display(); } }

步驟 4

執行程序,輸出結果:

Loading test_10mb.jpg Displaying test_10mb.jpg Displaying test_10mb.jpg


 

本文摘抄:http://www.runoob.com/design-pattern/design-pattern-tutorial.html若有違規,請聯繫我。我當即刪除
相關文章
相關標籤/搜索