23種設(shè)計(jì)模式之創(chuàng)建型模式

個(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;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容