天天看點

java設計模式之原型模式-淺克隆與深克隆

《2019年阿裡雲雙11活動拼團》: https://www.aliyun.com/1111/2019/group-buying-share 【限時】1年86元,3年229元,用來建站和程式設計學習【 附WordPress建站教程

定義:原型模式就是用原型執行個體指定建立對象的種類,并且通過複制這些原型建立新的對象。

在應用程式中,有些對象比較複雜,其建立過程過于複雜,而且我們又需要頻繁的利用該對象,如果這個時候我們按照正常思維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 + '\'' +

            '}';

}           
運作結果:

​           
​

通過對引用類型值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 + '\'' +

            '}';

}
           
運作結果:

​           

`

優點:

當建立對象的執行個體較為複雜的時候,使用原型模式可以簡化對象的建立過程。

直接操作二進制流,可以提高執行個體的建立效率。

缺點:

需要為每一個類配置一個克隆方法,而且該克隆方法位于類的内部,當對已有類進行改造的時候,需要修改代碼,違反了開閉原則。

在實作深克隆時需要編寫較為複雜的代碼,而且當對象之間存在多重簽到引用時,為了實作深克隆,每一層對象對應的類都必須支援深克隆,實作起來會比較麻煩。

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