Tip:由于23三種設計模式的篇幅較長,先來介紹我們比較熟悉的建造者模式。
單例模式中的單例是指唯一的實例對象。Java API中的Calendar類就利用了單例模式。相信大家應該對這條語句不陌生:Calendar.getInstance()。這條語句創建了一個單例。再如在某些應用場景下,需要重復獲取同一個實例對象,不斷new對象勢必會造成Java堆中的內存浪費,因此,我們可以把該對象單例化,達到重復利用統一資源的目的。
單例模式代碼:
/** * @author Hanlin Wang */public class SingletonMode { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance2 = Singleton.getInstance(); System.out.PRintln(instance==instance2); }}//懶漢式class Singleton{ //定義一個Singleton類型的變量。private防止外部訪問;static能夠以靜態方式獲??;null實現延遲加載。 private static Singleton instance = null; //私有化構造方法,防止外部創建該對象。 private Singleton(){} //synchronized方法:使單例對象創建時,線程安全。 private static synchronized void syncInit(){ if (null == instance) { instance = new Singleton(); } } //公共的、靜態的方法,獲取唯一的實例。 public static Singleton getInstance(){ if (null == instance) { syncInit(); } return instance; }}單例模式通過類創建唯一的實例對象。形如:Singleton.getInstance()。而我們經常通過Object obj = new Object();創建實例對象,一定要區分清楚:類創建實例對象是把new對象語句插入到該類的一個靜態方法中,從而可以以類名.方法名調用創建實例對象的方法。由于要通過類創建單例,必須把創建對象的方法加上static修飾符。要能訪問該方法,所以方法還要加上public修飾符。又由于靜態方法只能作用于靜態變量,所以單例對象的引用變量instance必須用static修飾,這樣instance靜態變量就被存入了方法區(詳見JVM虛擬機內存劃分概述)。防止外部直接訪問instance靜態變量,加上private修飾符。
還有大片細節需要大家去細心琢磨,代碼已上注釋。
工廠模式分為三大類:普通工廠模式、工廠方法模式、靜態工廠方法模式。
普通工廠模式內部定義一個生產方法,方法中接受一個參數,根據參數值的不同來創建相應的對象。
代碼:
//普通工廠模式class Factory{ public C produce(String type){ if ("A".equals(type)) { return new A(); } else if ("B".equals(type)) { return new B(); } else { return null; } }}//定義一個接口類Cinterface C{ void run();}//定義兩個實現類A、Bclass A implements C{ public void run(){ System.out.println("A's running"); }}class B implements C{ public void run(){ System.out.println("B's running"); }}public class FactoryMode { public static void main(String[] args) { /*普通工廠模式 Factory factory = new Factory(); C a = factory.produce("A"); C b = factory.produce("B"); a.run(); b.run();*/ }}可見,根據傳入參數名的不同來決定生產何類對象。
普通工廠模式通過傳入的參數來判斷創建何種對象,這樣存在一個問題,如下: public C produce(String type) 返回的是C類型,雖然這樣很好的利用了多態的特性,但我們無法得知返回的對象是C接口的哪一個實現類,A?還是B?。
因此,工廠方法模式通過在工廠類中定義一系列方法來實現精準創建具體類型的實力對象。
代碼:
//工廠方法模式class MethodFactory{ public A produceA(){ return new A(); } public B produceB(){ return new B(); }}//定義一個接口類Cinterface C{ void run();}//定義兩個實現類A、Bclass A implements C{ public void run(){ System.out.println("A's running"); }}class B implements C{ public void run(){ System.out.println("B's running"); }}public class FactoryMode { public static void main(String[] args) { MethodFactory factory = new MethodFactory(); A a = factory.produceA(); B b = factory.produceB(); a.run(); b.run(); }}靜態工廠方法模式與工廠方法模式類似,以靜態的方式調用工廠類的方法。我們只需在工廠方法模式的基礎上給工廠類中的方法加上static修飾符。
代碼:
//靜態工廠方法模式class StaticFactory{ public static A produceA(){ return new A(); } public static B produceB(){ return new B(); }}普通(class)工廠模式 VS 抽象(interface、abstract class)工廠模式。這么一形(dou)象(bi)的比較,相信大家肯定猜到區別了。抽象工廠模式把工廠類中的方法抽取出來放在了一個interface中,工廠類實現interface中的方法就是抽象工廠模式。由于是工廠類繼承工廠類接口,因此不能使用static關鍵字來修飾工廠類的方法。
代碼:
class Factory{ public C produce(String type){ if ("A".equals(type)) { return new A(); } else if ("B".equals(type)) { return new B(); } else { return null; } }}//定義一個接口類Cinterface C{ void run();}//定義兩個實現類A、Bclass A implements C{ public void run(){ System.out.println("A's running"); }}class B implements C{ public void run(){ System.out.println("B's running"); }}//抽象工廠模式。創建一個Provider,被各種工廠類實現。interface Provider{ C produce();}class FactoryA implements Provider{ public C produce(){ return new A(); }}class FactoryB implements Provider{ public C produce(){ return new B(); }}public class FactoryMode { public static void main(String[] args) { FactoryA factoryA = new FactoryA(); FactoryB factoryB = new FactoryB(); C a = factoryA.produce(); C b = factoryB.produce(); a.run(); b.run(); }}工廠模式專注于創建單一對象,建造者模式在工廠模式的基礎上側重對象的批量創建。
代碼:
/** * @author Hanlin Wang *///工廠模式關注的是創建單個產品,而建造者模式則關注創建符合對象,多個部分。因此,是選擇工廠模式還是建造者模式,依實際情況而定。public class BuilderMode { public static void main(String[] args) { Builder builder = new Builder(); builder.batchProduceA(10); builder.batchProduceB(15); }}class Builder{ private ArrayList<C> list = new ArrayList<C>(); public void batchProduceA(int count){ for (int i = 0; i < count; i++) { list.add(new A()); } } public void batchProduceB(int count){ for (int i = 0; i < count; i++) { list.add(new B()); } }}建造者模式通過for循環批量創建了A、B對象,并將A、B對象存儲到List集合對象中。
原型模式用于克隆對象。原型模式克隆分淺克隆和深克隆。利用原型模式克隆,可以適當代替new對象這一操作,擁有new對象所不具備的,賦值屬性,對象狀態等等。
淺克隆只克隆對象本身,不克隆對象屬性,而克隆對象屬性的引用。
深克隆不但克隆對象本身,還克隆了對象的屬性,是完全唯一的。若實現序列化接口,還可進行序列化和反序列化操作。
代碼:
import java.io.IOException;import java.util.ArrayList;/** * @author Hanlin Wang */public class PrototypeMode { public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException { Prototype proto = new Prototype(); Prototype clone1 = (Prototype) proto.clone(); Prototype clone2 = (Prototype) proto.clone(); System.out.println(clone1 == clone2); System.out.println(clone1.getInfo() == clone2.getInfo()); Prototype deepClone1 = (Prototype) proto.deepClone(); Prototype deepClone2 = (Prototype) proto.deepClone(); System.out.println(deepClone1 == deepClone2); System.out.println(deepClone1.getInfo() == deepClone2.getInfo()); /*false true false false*/ }}class Prototype implements Cloneable{ private ArrayList<String> info = new ArrayList<String>(); public ArrayList<String> getInfo() { return info; } public void setInfo(ArrayList<String> info) { this.info = info; } //淺克隆 public Object clone() throws CloneNotSupportedException{ Prototype proto = (Prototype) super.clone(); return proto; } //深克隆 public Object deepClone() throws CloneNotSupportedException{ Prototype proto = (Prototype) super.clone(); proto.info = (ArrayList<String>) info.clone(); return proto; }}以上就是Java設計模式中創建型模式的概述,相信大家應該有所收獲。
讀者朋友也可以給我留言,我會認真回復,什么類型的意見建議都可以,歡迎討論。
隨后我會推出后續的有關設計模式的博文,我們不見不散~
新聞熱點
疑難解答