java設計模式 - 原型(乾貨)

 深度講解23種設計模式,力爭每種設計模式都刨析到底。廢話很少說,開始第二種設計模式 - 原型。設計模式

1、爲何有原型模式ide

 當一個類須要克隆的時候,咱們總不但願new一個對象,而後逐個屬性去設置值。 這個時候,咱們亟需一種this

高效的對象copy方法,原型設計模式應運而生。spa

 

2、原型設計模式寫法設計

 原型設計模式實現:指針

public class Person implements Cloneable {

private String userName;

private String sex;

private int age;

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
return person;
}

@Override
public String toString() {
return "Person{" +
"userName='" + userName + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person();
p.setAge(19);
p.setUserName("小明");
p.setSex("男");
Person p1 = p.clone();

System.out.println(p.hashCode());
System.out.println(p1.hashCode());

p.setAge(12);

System.out.println(p);
System.out.println(p1);
}
執行結果

  

 

 原型實現,在Person類中,實現了Cloneable 接口,而後重寫clone方法,便可。對象

 一切看似都很美好,然而,若是在Person中增長一個不是基本類型,也不是String類型的屬性時,狀況會令你意外。blog

 1,淺拷貝接口

public class Person implements Cloneable {

private String userName;

private String sex;

private int age;

private Son son;

public Son getSon() {
return son;
}

public void setSon(Son son) {
this.son = son;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
return person;
}

@Override
public String toString() {
return "Person{" +
"userName='" + userName + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", son=" + son +
'}';
}
}
public class Son {

private String sonName;

public String getSonName() {
return sonName;
}

public void setSonName(String sonName) {
this.sonName = sonName;
}

@Override
public String toString() {
return "Son{" +
"sonName='" + sonName + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person();
p.setAge(19);
p.setUserName("小明");
p.setSex("男");
Son son = new Son();
son.setSonName("小明的孩子");
p.setSon(son);
Person p1 = p.clone();

System.out.println(p.hashCode());
System.out.println(p1.hashCode());

p1.getSon().setSonName("隔壁老王的孩子");
p1.setAge(12);

System.out.println(p);
System.out.println(p1);
}
}
運行結果以下

  

 那麼爲何可以出現這樣的結果呢?get

 由於clone方法並不能穿透到son,也就是p和p1公用了son對象(p1對象對son的clone只是copy了指針,並無徹底copy,也就是淺拷貝),因此p和p1同時輸出的「隔壁老王的孩子」。

 

 

  若是咱們但願實現完整的clone,該如何處理呢?咱們須要深拷貝。

 2,深拷貝

  1)套娃式深拷貝

  咱們在淺拷貝的基礎上修改,修改部分筆者用紅色標識。

public class Person implements Cloneable {

private String userName;

private String sex;

private int age;

private Son son;

public Son getSon() {
return son;
}

public void setSon(Son son) {
this.son = son;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
protected Person clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.setSon(person.getSon().clone());
return person;
}

@Override
public String toString() {
return "Person{" +
"userName='" + userName + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", son=" + son +
'}';
}
}

public class Son implements Cloneable {

private String sonName;

public String getSonName() {
return sonName;
}

public void setSonName(String sonName) {
this.sonName = sonName;
}

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

@Override
protected Son clone() throws CloneNotSupportedException {
return (Son) super.clone();
}
}
咱們再來看結果:

  

  很顯然,獲得了咱們指望的結果,像不像套娃?

  2)序列化深拷貝

  首先改造Person

public class Person implements Serializable {

private String userName;

private String sex;

private int age;

private Son son;

public Son getSon() {
return son;
}

public void setSon(Son son) {
this.son = son;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "Person{" +
"userName='" + userName + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", son=" + son +
'}';
}
}
接着,改造Son
public class Son implements Serializable {

private String sonName;

public String getSonName() {
return sonName;
}

public void setSonName(String sonName) {
this.sonName = sonName;
}

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

}
Main方法
public class Test {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Person p = new Person();
p.setAge(19);
p.setUserName("小明");
p.setSex("男");
Son son = new Son();
son.setSonName("小明的孩子");
p.setSon(son);

ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(p);

ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
Person p1= (Person) ois.readObject();


System.out.println(p.hashCode());
System.out.println(p1.hashCode());

p1.getSon().setSonName("隔壁老王的孩子");
p1.setAge(12);

System.out.println(p);
System.out.println(p1);
}
}
來看看輸出結果:

  

 很顯然,獲得了咱們指望的結果。

 固然,能夠把序列化過程封裝到Person中。沒有了套娃,又能夠歡樂玩耍了。

 總結:每一種拷貝都有本身的應用場景,要看具體的業務場景。

相關文章
相關標籤/搜索