java設計模式之原型模式

定義:原型模式就是用原型實例指定創建對象的種類,並且通過複製這些原型創建新的對象。

在應用程序中,有些對象比較複雜,其創建過程過於複雜,而且我們又需要頻繁的利用該對象,如果這個時候我們按照常規思維new該對象,那麼務必會造成資源浪費,這個時候我們就希望可以利用一個已有的對象來不斷對他進行復制就好了,這就是編程中的“克隆”。原型模式直接操作底層二進制流,在創建複雜對象是效率提升明顯。

UML類圖:

淺克隆與深克隆:

  • 淺克隆:當原型對象被複制時,只複製它本身和其中包含的值類型的成員變量,而引用類型的成員變量並沒有複製。
  • 深克隆:除了對象本身被複制外,對象所包含的所有成員變量也將被複制。

淺克隆:

public class Person implements Cloneable {
    private String name;
    private boolean gender;
    private Interest interest;

    public Person(String name, boolean gender, Interest interest) {
        this.name = name;
        this.gender = gender;
        this.interest = interest;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public boolean isGender() {
        return gender;
    }
    public void setGender(boolean gender) {
        this.gender = gender;
    }
    public Interest getInterest() {
        return interest;
    }
    public void setInterest(Interest interest) {
        this.interest = interest;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender=" + gender +
                ", interest=" + interest +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Interest interest = new Interest("攝影");
        Person gg = new Person("gg",false,interest);
        System.out.println(gg);
        Person dxy = (Person)gg.clone();
        dxy.setName("dxy");
        dxy.setGender(true);
        dxy.interest.setName("咖啡");
        System.out.println(dxy);
        System.out.println(gg);
    }
}
class Interest{
    private String name;

    public Interest(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Interest{" +
                "name='" + name + '\'' +
                '}';
    }
}

運行結果:

Person{name='gg', gender=false, interest=Interest{name='攝影'}}
Person{name='dxy', gender=true, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='咖啡'}}

淺克隆對於引用類型,只克隆了引用,因此兩個對象的interest公共同一個內存地址,一個對象變化,會引起另一個對象響應的變化。

深克隆:

public class Person implements Cloneable {
    private String name;
    private boolean gender;
    private Interest interest;

    public Person(String name, boolean gender, Interest interest) {
        this.name = name;
        this.gender = gender;
        this.interest = interest;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public boolean isGender() {
        return gender;
    }
    public void setGender(boolean gender) {
        this.gender = gender;
    }
    public Interest getInterest() {
        return interest;
    }
    public void setInterest(Interest interest) {
        this.interest = interest;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender=" + gender +
                ", interest=" + interest +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();  //直接調用object對象的clone()方法!
        //添加如下代碼實現深複製(deep Clone)
        Person person = (Person) obj;
        person.interest = (Interest)this.interest.clone(); //把屬性也進行克隆!
        return obj;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Interest interest = new Interest("攝影");
        Person gg = new Person("gg",false,interest);
        System.out.println(gg);
        Person dxy = (Person)gg.clone();
        dxy.setName("dxy");
        dxy.setGender(true);
        dxy.interest.setName("咖啡");
        System.out.println(dxy);
        System.out.println(gg);
    }
}
class Interest implements Cloneable {
    private String name;

    public Interest(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Interest{" +
                "name='" + name + '\'' +
                '}';
    }
}

運行結果:

Person{name='gg', gender=false, interest=Interest{name='攝影'}}
Person{name='dxy', gender=true, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='攝影'}}

通過對引用類型值Interest添加clone方法,並且對Person對象的clone方法改造,實現深克隆。

 

此外還可以通過序列化和反序列化的方式實現深複製。

public class Person implements Serializable {
    private String name;
    private boolean gender;
    private Interest interest;

    public Person(String name, boolean gender, Interest interest) {
        this.name = name;
        this.gender = gender;
        this.interest = interest;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public boolean isGender() {
        return gender;
    }
    public void setGender(boolean gender) {
        this.gender = gender;
    }
    public Interest getInterest() {
        return interest;
    }
    public void setInterest(Interest interest) {
        this.interest = interest;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender=" + gender +
                ", interest=" + interest +
                '}';
    }

    public static void main(String[] args) throws CloneNotSupportedException,ClassNotFoundException,IOException {
        Interest interest = new Interest("攝影");
        Person gg = new Person("gg",false,interest);
        System.out.println(gg);
        //使用序列化和反序列化實現深複製
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(gg);
        byte[] bytes = bos.toByteArray();

        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bis);

        Person dxy = (Person) ois.readObject();   //克隆好的對象!
        dxy.interest.setName("咖啡");

        System.out.println(dxy);
        System.out.println(gg);
    }
}
class Interest implements Serializable{
    private String name;

    public Interest(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Interest{" +
                "name='" + name + '\'' +
                '}';
    }
}

運行結果:

Person{name='gg', gender=false, interest=Interest{name='攝影'}}
Person{name='gg', gender=false, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='攝影'}}

優點:

  • 當創建對象的實例較爲複雜的時候,使用原型模式可以簡化對象的創建過程。
  • 直接操作二進制流,可以提高實例的創建效率。

缺點:

  • 需要爲每一個類配置一個克隆方法,而且該克隆方法位於類的內部,當對已有類進行改造的時候,需要修改代碼,違反了開閉原則。
  • 在實現深克隆時需要編寫較爲複雜的代碼,而且當對象之間存在多重簽到引用時,爲了實現深克隆,每一層對象對應的類都必須支持深克隆,實現起來會比較麻煩。

此外clone對象時,不調用構造方法,無視構造方法的權限。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章