目录
一、应用场景
原型模式就是利用一个对象去创建另一个对象,就是C++中的拷贝构造。
如果通过new创建一个对象需要非常繁琐的数据准备或访问权限设置,则可以使用原型模式。以某个对象为原型,复制出新的对象,新的对象具有原型对象的特点。
优点: 效率高(直接克隆,避免了重新执行构造过程的步骤)
克隆类似于new,但new创建新的对象属性使用的是默认值,克隆了的对象的属性值和原型对象相同。
二、原型模式的实现
1. Cloneable接口和clone方法
定义一个原型模式类,需要implements Cloneable接口,然后重写clone()方法
class MyProtoType implements Cloneable{
@Override
public Object clone(){
return null;
}
}
查看Cloneable接口的原码
Cloneable接口其实是一个空接口,implements Cloneable其实只是实现一个标记,标记说明这是一个实现了接口的原型类,可以在其中使用clone()方法。 @Override 了一个clone() 方法,其实这个方法可以任意命名,只需要加上@Override注释即可。
克隆分为浅克隆和深克隆两种。
2.浅克隆与深克隆
浅克隆:8种基本数据类型直接赋值,高级类型引用外部数据源的地址;当数据源改变时,克隆对象的内容也会改变。
深克隆:8种基本数据类型直接赋值,高级类型会分配内存并重新赋值;当数据源改变时,克隆对象的内容不会改变。
(1)浅克隆
原型模式中实现起来最困难的地方就是内存复制操作,但在Java中提供了clone()方法使这一过程变得简单。
我们写一个浅克隆的原型模式。以绵羊多利为原型创建克隆羊多利。当克隆之后,改变数据源时,看看克隆对象的内容是否会改变。
public class Sheep implements Cloneable{
private String name; //名字
private Date birthday; //出生日期
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getName() {
return name;
}
public Sheep(String name, Date date) {
this.name = name;
this.birthday = date;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException{
Object object = super.clone(); //只是调用了Object的clone()方法,没有对birthday进行clone()
return object;
}
}
测试代码:
public class MainTest {
public static void main(String[] args) throws CloneNotSupportedException, ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("1996-07-05 12:00:00");
Sheep sheep = new Sheep("原多利", date);
System.out.println(sheep.getName());
System.out.println(sheep.getBirthday());
System.out.println(sheep);
Sheep sheep2 = (Sheep) sheep.clone();
sheep2.setName("克隆多利");
System.out.println(sheep2.getName());
System.out.println(sheep2.getBirthday());
System.out.println(sheep2);
//更改原生日信息
date.setTime(0L);
//重新打印新克隆羊的信息
System.out.println(sheep.getBirthday());
System.out.println(sheep2.getBirthday());
}
}
测试结果
(2)深克隆
public class Sheep implements Cloneable{
private String name;
private Date birthday;
public Sheep(String name, Date date) {
this.name = name;
this.birthday = date;
}
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;
}
/**
* 重写克隆方法
*/
public Object clone() throws CloneNotSupportedException{
Object object = super.clone();
Sheep sheep = (Sheep) object;
sheep.birthday = (Date) this.birthday.clone(); //将具体的内容克隆一遍,实现深克隆
return sheep;
}
}
深克隆在clone()方法中,将非基本类型的属性clone()了一次,为其分配了内存并赋值,当改变源信息时,克隆对象的内容不会改变。
测试代码
public class MainTest {
public static void main(String[] args) throws CloneNotSupportedException, ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("1996-07-05 12:00:00");
Sheep sheep = new Sheep("原多利", date);
System.out.println(sheep.getName());
System.out.println(sheep.getBirthday());
System.out.println(sheep);
Sheep sheep2 = (Sheep) sheep.clone();
sheep2.setName("克隆多利");
System.out.println(sheep2.getName());
System.out.println(sheep2.getBirthday());
System.out.println(sheep2);
//更改原生日信息
date.setTime(0L);
//重新打印新克隆羊的信息
System.out.println(sheep.getBirthday());
System.out.println(sheep2.getBirthday());
}
}
测试结果