- 适用场景
类初始化消耗较多资源
new产生的一个对象需要非常繁琐的过程(数据准备,访问权限等)
构造函数比较复杂的过程
循环体中生成大量对象时
- 优点
原型模式性能上比直接new一个对象性能高
简化创建过程
- 确定
必须配备克隆方法
对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
深拷贝和浅克隆要使用得当
示例代码
public class Mail implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
private String content;
private String address;
@Override
public Mail clone() throws CloneNotSupportedException {
return (Mail) super.clone();
}
}
public class MailUtil {
public static void sendMail(Mail mail){
String content="发送给{0},内容为{1},地址未{2}";
System.out.println(MessageFormat.format(content,mail.getName(),mail.getContent(),mail.getAddress())+mail.toString());
}
public static void saveOriginMail(Mail mail){
System.out.println("存储originMail"+mail.getContent()+mail.toString());
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Mail originMail=new Mail();
originMail.setContent("初始内容");
for(int i=0;i<5;i++){
Mail cloneMail= (Mail) (originMail.clone());
cloneMail.setName("姓名"+i);
cloneMail.setContent("克隆内容");
cloneMail.setAddress("地址"+i);
MailUtil.sendMail(cloneMail);
}
MailUtil.saveOriginMail(originMail);
}
}
输出内容
发送给姓名0,内容为克隆内容,地址未地址0com.pattern.create.prototype.Mail@4554617c
发送给姓名1,内容为克隆内容,地址未地址1com.pattern.create.prototype.Mail@74a14482
发送给姓名2,内容为克隆内容,地址未地址2com.pattern.create.prototype.Mail@1540e19d
发送给姓名3,内容为克隆内容,地址未地址3com.pattern.create.prototype.Mail@677327b6
发送给姓名4,内容为克隆内容,地址未地址4com.pattern.create.prototype.Mail@14ae5a5
存储originMail初始内容com.pattern.create.prototype.Mail@7f31245a
可以发现clone对象不需要调用对象的构造方法,输出了不同对象。
关于深拷贝和浅拷贝
public class Pig implements Cloneable{
private String name;
public Pig(String name, Date birthDay) {
this.name=name;
this.birthDay=birthDay;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
private Date birthDay;
@Override
public Pig clone() throws CloneNotSupportedException {
return (Pig) super.clone();
}
}
Test类
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Pig pig1=new Pig("佩奇",new Date(0L));
Pig pig2=pig1.clone();
System.out.println(pig1);
System.out.println(pig2);
pig1.setName("佩奇1");
System.out.println(pig1.getName());
System.out.println(pig2.getName());
pig1.getBirthDay().setTime(88888888888L);
System.out.println(pig1.getBirthDay());
System.out.println(pig2.getBirthDay());
pig1.setBirthDay(new Date(99999999999999L));
System.out.println(pig1.getBirthDay());
System.out.println(pig2.getBirthDay());
}
}
输出
com.pattern.create.prototype.clone.Pig@4554617c
com.pattern.create.prototype.clone.Pig@74a14482
佩奇1
佩奇
Thu Oct 26 03:21:28 CST 1972
Thu Oct 26 03:21:28 CST 1972
Wed Nov 16 17:46:39 CST 5138
Thu Oct 26 03:21:28 CST 1972
浅拷贝:
①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。
②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
改为深拷贝的方法
@Override
public Pig clone() throws CloneNotSupportedException {
Pig clonePig=(Pig) super.clone();
//深克隆
clonePig.birthDay= (Date) clonePig.birthDay.clone();
return clonePig;
}