一、使用场景
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() 方法,返回单例对象即可。