個(gè)人博客: http://zhangsunyucong.top
前言
本文主要是介紹5種創(chuàng)建型模式中,除了單例模式外的其他創(chuàng)建型模式,包括建造者模式,工廠模式,抽象工廠模式,原型模式。
1、建造者模式,可以將對(duì)象的表現(xiàn)和創(chuàng)建(實(shí)現(xiàn))分離開(kāi)來(lái),根據(jù)不同的創(chuàng)建步驟可以產(chǎn)生不同的對(duì)象,而對(duì)象的創(chuàng)建也是一次性的,創(chuàng)建后的對(duì)象是不可變。
2、工廠模式,根據(jù)形式的不同,工廠模式可以分為簡(jiǎn)單工廠方法模式、多工廠方法模式和抽象工廠方法模式。在簡(jiǎn)單工廠方法模式中只有一個(gè)工廠方法,工廠方法根據(jù)不同的條件生產(chǎn)不同的對(duì)象。多工廠方法模式,為每一個(gè)對(duì)象都提供一個(gè)工廠方法。抽象工廠方法模式,就是在多工廠方法模式的基礎(chǔ)上將每個(gè)普通工廠方法變?yōu)殪o態(tài)工廠方法。另外,可以使用反射來(lái)生產(chǎn)產(chǎn)品。
3、抽象工廠模式,它是工廠模式的進(jìn)一步抽象,它將產(chǎn)品和工廠都抽象為一個(gè)接口,每個(gè)具體的工廠生產(chǎn)一種具體的產(chǎn)品。
其實(shí)它們的特點(diǎn)是,簡(jiǎn)單工廠方法模式,用一個(gè)方法來(lái)生產(chǎn)各種產(chǎn)品。多工廠方法模式,一種對(duì)象對(duì)應(yīng)一個(gè)方法。抽象工廠方法模式,在多工廠方法模式的基礎(chǔ)上,進(jìn)一步的將每個(gè)方法都變?yōu)殪o態(tài)的,這樣子就不需要?jiǎng)?chuàng)建工廠對(duì)象了。抽象工廠模式,它將產(chǎn)品和工廠都進(jìn)一步抽象為一個(gè)類(lèi)或者接口。
一個(gè)方法=》多個(gè)方法=》多個(gè)靜態(tài)方法=》抽象類(lèi)(接口)
4、原型模式,就是從一個(gè)已經(jīng)存在的對(duì)象(原型)通過(guò)克隆和復(fù)制創(chuàng)建一個(gè)對(duì)象。復(fù)制分為淺復(fù)制和深復(fù)制。
淺復(fù)制和深復(fù)制的區(qū)別:
淺復(fù)制:將一個(gè)對(duì)象復(fù)制后,基本數(shù)據(jù)類(lèi)型的變量都會(huì)重新創(chuàng)建,而引用類(lèi)型,指向的還是原對(duì)象所指向的。
深復(fù)制:將一個(gè)對(duì)象復(fù)制后,不論是基本數(shù)據(jù)類(lèi)型還有引用類(lèi)型,都是重新創(chuàng)建的。簡(jiǎn)單來(lái)說(shuō),就是深復(fù)制進(jìn)行了完全徹底的復(fù)制,而淺復(fù)制不徹底。
建造者模式
public class BuilderTest {
private String basic;//地基
private String wall;//墻
private String roofed;//樓頂
private BuilderTest() {}
private BuilderTest(Builder builder) {
this.basic = builder.basic;
this.wall = builder.wall;
this.roofed = builder.roofed;
}
public void doSomeThing() {
}
public static class Builder {
private String basic;//地基
private String wall;//墻
private String roofed;//樓頂
public Builder setBasic(String basic) {
this.basic = basic;
return this;
}
public Builder setWall(String wall) {
this.wall = wall;
return this;
}
public Builder setRoofed(String roofed) {
this.roofed = roofed;
return this;
}
public BuilderTest create() {
BuilderTest builderTest = new BuilderTest(this);
return builderTest;
}
}
}
BuilderTest的構(gòu)造函數(shù)都是私有的,只在Builder中創(chuàng)建它的實(shí)例。Builder是一個(gè)公開(kāi)的靜態(tài)內(nèi)部類(lèi),它的內(nèi)部成員變量都是私有的,只能調(diào)用相對(duì)應(yīng)的setter方法設(shè)置,并和BuilderTest中的成員變量是一樣的,每個(gè)setter方法都是返回Builder自身的,可以鏈?zhǔn)降恼{(diào)用,當(dāng)調(diào)用create時(shí)會(huì)將變量傳遞給BuilderTest和一次性初始化BuilderTest實(shí)例。
實(shí)際使用:
BuilderTest builderTest = new BuilderTest.Builder()
.setBasic("basic")
.setWall("wall")
.setRoofed("roofed")
.create();
builderTest.doSomeThing();
工廠模式
簡(jiǎn)單工廠方法模式
規(guī)范產(chǎn)品接口:
public interface Product {
void sayHello();
}
產(chǎn)品類(lèi):
ProductA.java
public class ProductA implements Product {
@Override
public void sayHello() {
System.out.print("Helle ! My name is ProductA");
}
}
ProductB.java
public class ProductB implements Product {
@Override
public void sayHello() {
System.out.print("Hello, My name is ProductB");
}
}
簡(jiǎn)單工廠類(lèi)
public class SimpleFactoryTest {
public Product createProduct(String name) {
if("ProductA".equals(name)) {
return new ProductA();
} else if("ProductB".equals(name)) {
return new ProductB();
} else {
System.out.print("沒(méi)有找到產(chǎn)品,請(qǐng)輸入正確的類(lèi)型!");
return null;
}
}
}
使用:
SimpleFactoryTest simpleFactoryTest = new SimpleFactoryTest();
Product productA = simpleFactoryTest.createProduct("ProductA");
productA.sayHello();
Product ProductB = simpleFactoryTest.createProduct("ProductB");
ProductB.sayHello();
多工廠方法模式
MultiMethodFactory.java
public class MultiMethodFactory {
public Product createProductA() {
return new ProductA();
}
public Product createProductB() {
return new ProductB();
}
}
使用:
MultiMethodFactory multiMethodFactory = new MultiMethodFactory();
Product productA = multiMethodFactory.createProductA();
productA.sayHello();
Product productB = multiMethodFactory.createProductB();
productB.sayHello();
靜態(tài)工廠方法模式
public class StaticMethodFactory {
public static Product createProductA() {
return new ProductA();
}
public static Product createProductB() {
return new ProductB();
}
}
使用:
Product productA = StaticMethodFactory.createProductA();
Product productB = StaticMethodFactory.createProductB();
productA.sayHello();
productB.sayHello();
抽象工廠模式
產(chǎn)品模版:
public interface Product {
void sayHello();
}
ProductA.java
public class ProductA implements Product {
@Override
public void sayHello() {
System.out.print("Helle ! My name is ProductA");
}
}
ProductB.java
public class ProductB implements Product {
@Override
public void sayHello() {
System.out.print("Hello, My name is ProductB");
}
}
工廠模版:
public interface Factory {
Product createProduct();
}
ProductAFactory.java
public class ProductAFactory implements Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
ProductBFactory.java
public class ProductBFactory implements Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
使用:
ProductAFactory productAFactory = new ProductAFactory();
productAFactory.createProduct();
ProductBFactory productBFactory = new ProductBFactory();
productBFactory.createProduct();
原型模式
原型模式的關(guān)鍵是實(shí)現(xiàn)Cloneable接口,并重寫(xiě)Object的clone函數(shù),Cloneable是一個(gè)空接口。
public class PrototypeObject implements Cloneable {
public int intValue = 34;
public String strValue = "I am the First value";
public ProductA productA = new ProductA();
@Override
public Object clone() throws CloneNotSupportedException {
PrototypeObject prototypeObject = (PrototypeObject)super.clone();
return prototypeObject;
}
@Override
public String toString() {
return "intValue=" + intValue
+ "strValue=" + strValue
+ "helloTxt=" + productA.helloTxt;
}
}
ProductA.java
public class ProductA implements Product {
public String helloTxt = "Helle ! My name is ProductA";
@Override
public void sayHello() {
System.out.print("Helle ! My name is ProductA");
}
}
使用:
try {
PrototypeObject prototypeObject = new PrototypeObject();
PrototypeObject prototypeObjectClone = (PrototypeObject)prototypeObject.clone();
Log.d("hyj", "改變克隆對(duì)象值之前:"
+ "prototypeObject=>" + prototypeObject.toString());
prototypeObjectClone.strValue = "I am the second value";
prototypeObjectClone.productA.helloTxt = "Hi, I am here and change something";
Log.d("hyj", "改變克隆對(duì)象值之后:"
+ "prototypeObject=>" + prototypeObject.toString());
Log.d("hyj", "改變克隆對(duì)象值之后:"
+ "prototypeObjectClone=>" + prototypeObjectClone.toString());
} catch (CloneNotSupportedException e) {
System.out.print(e.getCause());
}
運(yùn)行結(jié)果:
改變克隆對(duì)象值之前:prototypeObject=>intValue=34strValue=I am the First valuehelloTxt=Helle ! My name is ProductA
改變克隆對(duì)象值之后:prototypeObject=>intValue=34strValue=I am the First valuehelloTxt=Hi, I am here and change something
改變克隆對(duì)象值之后:prototypeObjectClone=>intValue=34strValue=I am the second valuehelloTxt=Hi, I am here and change something
在Object中,
Object#clone
protected Object clone() throws CloneNotSupportedException {
if (!(this instanceof Cloneable)) {
throw new CloneNotSupportedException("Class " + getClass().getName() +
" doesn't implement Cloneable");
}
return internalClone();
}
/*
* Native helper method for cloning.
*/
private native Object internalClone();
可以看出,Object的clone方法會(huì)調(diào)用native函數(shù)internalClone;
上面提到原型模式是一種淺復(fù)制,將一個(gè)對(duì)象復(fù)制后,基本數(shù)據(jù)類(lèi)型的變量都會(huì)重新創(chuàng)建,而引用類(lèi)型,指向的還是原對(duì)象所指向的。而要徹底重新克隆和創(chuàng)建對(duì)象,需要使用深復(fù)制。
深復(fù)制,可以使用對(duì)象的序列化來(lái)實(shí)現(xiàn)。
public class PrototypeObject implements Cloneable, Serializable {
public int intValue = 34;
public String strValue = "I am the First value";
public ProductA productA = new ProductA();
/* 淺復(fù)制 */
@Override
public Object clone() throws CloneNotSupportedException {
PrototypeObject prototypeObject = (PrototypeObject)super.clone();
return prototypeObject;
}
/* 深復(fù)制 */
public Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
@Override
public String toString() {
return "intValue=" + intValue
+ "strValue=" + strValue
+ "helloTxt=" + productA.helloTxt;
}
}