一、使用場景
1.類初始化消耗資源較多
2.new產生的對象需要非常繁瑣的過程(權限認證、數據準備)
3.構造函數比較複雜
4.循環體中產生大量對象
在Spring中原型模式應用的也非常廣泛,比如scope="prototype",我們常用的JOSN.parseObject();就是原型模式的一種
二、原型模式的使用
簡單克隆
一個簡單的原型模式代碼,這樣的設計。先創建原型接口 Prototype
package Prototype;
public interface Prototype {
Prototype clone();
}
創建需要具體克隆的對象 PrototypeA
package Prototype;
import lombok.Data;
import java.util.List;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:15:23
*/
@Data //記得引入lombok包即可
public class PrototypeA implements Prototype {
private String name;
private int age;
private List<String> hobby;
@Override
public PrototypeA clone() {
PrototypeA a = new PrototypeA();
a.setAge(this.age);
a.setName(this.name);
a.setHobby(this.hobby);
return a;
}
}
創建Client對象
package Prototype;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:15:35
*/
public class Client {
private Prototype prototype;
public Client(Prototype prototype){
this.prototype = prototype;
}
public Prototype startClone(Prototype startPototype){
return startPototype.clone();
}
}
測試代碼:
package Prototype;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:15:38
*/
public class PrototypeTest {
public static void main(String[] args){
PrototypeA p1 = new PrototypeA();
p1.setName("JY");
p1.setAge(21);
List list =new ArrayList(3);
list.add("籃球");
p1.setHobby(list);
System.out.println(p1);
Client client = new Client(p1);
PrototypeA prototypeA = (PrototypeA)client.startClone(p1);
System.out.println(prototypeA);
//淺克隆,克隆引用對象,其引用對象主要是克隆地址
System.out.println("引用對象地址比較:"+ (p1.getHobby() == prototypeA.getHobby()));
System.out.println("對象地址比較:"+ (p1 == prototypeA ));
}
}
總結:從測試結果可以看出我們克隆的只是引用對象的地址。也就是所有的引用對象都是指向原來的對象,這就是淺克隆。
深度克隆
我們都知道漩渦鳴人,他的分身術,他可以分出許多分身可不是每個分身都能使用九尾,所以我希望實現讓每個分身都能使用九尾,那每個九尾都是獨一無二了。
先創建鳴人Naruto 對象:
package Prototype.Degree;
import java.util.Date;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:16:17
*/
public class Naruto {
private String name;
private int age;
private Date brithday;
}
創建九尾Ninetails對象:
package Prototype.Degree;
import java.io.Serializable;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:16:20
*/
public class Ninetails implements Serializable {
private String Hurt; //傷害
private String blood; //血量
}
創建漩渦鳴人XUNaruto對象:
package Prototype.Degree;
import java.io.*;
import java.util.Date;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:16:25
*/
public class XUNaruto extends Naruto implements Cloneable, Serializable {
public Ninetails ninetails; //九尾
public XUNaruto(){
this.brithday = new Date();
this.ninetails = new Ninetails();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return this.deepClone();
}
public Object deepClone(){
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
XUNaruto copy = (XUNaruto)ois.readObject();
copy.brithday = new Date();
return copy;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
public XUNaruto Deep(XUNaruto xuNaruto){
XUNaruto x = new XUNaruto();
x.age = xuNaruto.age;
x.name = xuNaruto.name;
x.brithday = new Date();
x.ninetails = xuNaruto.ninetails;
return x;
}
}
創建測試類NarutoTest對象:
package Prototype.Degree;
/**
* Created with IDEA
* author:Jy
* Date:2020/3/24
* Time:16:36
*/
public class NarutoTest {
public static void main(String[] args){
XUNaruto xu = new XUNaruto();
//深克隆(每個分身都有獨立的九尾)
try {
XUNaruto a = (XUNaruto)xu.clone();
System.out.println("深克隆:"+(xu.ninetails == a.ninetails));
}catch (Exception e){
e.printStackTrace();
}
//淺克隆(每個分身只有九尾的引用)
XUNaruto xu1 = new XUNaruto();
XUNaruto b = xu1.Deep(xu1);
System.out.println("淺克隆:"+(xu1.ninetails == b.ninetails));
}
}
總結:如果我們克隆的對象是單例對象,這就意味着深克隆會破壞單例。解決思路,禁止深克隆。也可以實現 Cloneable接口,重寫 clone() 方法,返回單例對象即可。