1.原型模式介绍
原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。
原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。
2.克隆实现原型模式
原型模式就是通过“复制”一个已经存在的实例来返回新的实例,然后修改新实例的属性来获得想要的对象。这一点相信很好理解,重要的是了解怎么完全克隆一个已经存在的实例来获得一个新的实例。克隆分为浅克隆和深克隆,下面我们通过一个例子来理解一下两种克隆的区别。
- 浅克隆。这里写了一个Sheep类实现了Cloneable接口,一个测试类Client。代码如下。
package prototype;
import java.util.Date;
/**
*浅克隆Sheep类。
*/
public class Sheep implements Cloneable {
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep(String name, Date birthday) {
this.sname = name;
this.birthday = birthday;
}
}
package prototype;
import java.util.Date;
/**
1. 测试原型模式(浅克隆)
*/
public class Client {
public static void main(String[] args) {
Date date = new Date(123465421L);
Sheep sheep1 = new Sheep("多利", date);
System.out.println("===============原型=================");
System.out.println(sheep1);
System.out.println(sheep1.getSname());
System.out.println(sheep1.getBirthday());
System.out.println("===================================");
try {
Sheep sheep2 = (Sheep) sheep1.clone();
System.out.println(sheep2);
System.out.println(sheep2.getSname());
System.out.println(sheep2.getBirthday());
//拷贝后可以直接更改属性来获得想要的对象
sheep2.setSname("少利");
System.out.println(sheep2.getSname());
//这里改变原型引用的Date对象发现克隆的对象的属性也跟着改变了
date.setTime(4564532154L);
System.out.println(sheep2.getBirthday());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
这时候可以发现改变原型对象(sheep1)的birthday属性引用的Date对象(date)的时候,克隆对象(sheep2)的属性(birthday)也跟着改变了。这是因为原型对象(sheep1)和克隆对象(sheep2)的birthday引用的是同一个对象。这就是浅拷贝的简单例子,拷贝的是原型属性的引用。
- 深拷贝。代码和上面基本相同。但是,在Sheep0类的拷贝方法中,先调用父类(Object)的clone方法获得了原型对象的浅拷贝对象,然后再调用birthday.clone方法获得了原型对象的birthday属性的拷贝,然后再把浅拷贝对象的birthday属性设置成了原型的birthday属性的拷贝(Date类实现了Cloneable接口)。这样拷贝对象得到的就是一个完全的拷贝了。代码如下。
package prototype;
import java.util.Date;
/**
* 深克隆Sheep类
*/
public class Sheep0 implements Cloneable {
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Sheep0 sheep = (Sheep0)obj;
sheep.birthday = (Date)this.birthday.clone();
return obj;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep0(String name, Date birthday) {
this.sname = name;
this.birthday = birthday;
}
}
package prototype;
import java.util.Date;
/**
1. 测试原型模式(深克隆)
*/
public class Client2 {
public static void main(String[] args) {
Date date = new Date(123465421L);
Sheep0 sheep1 = new Sheep0("多利", date);
System.out.println("===============原型=================");
System.out.println(sheep1);
System.out.println(sheep1.getSname());
System.out.println(sheep1.getBirthday());
System.out.println("===================================");
//浅克隆
try {
Sheep0 sheep2 = (Sheep0)sheep1.clone();
System.out.println(sheep2);
System.out.println(sheep2.getSname());
System.out.println(sheep2.getBirthday());
sheep2.setSname("少利");
System.out.println(sheep2.getSname());
//改变原型对象的属性 此时克隆对象的属性不变
date.setTime(4564532154L);
System.out.println("原型birthday:" + sheep1.getBirthday());
System.out.println("克隆birthday:" + sheep2.getBirthday());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
这时可以发现改变原型对象的引用属性后,克隆对象的对应属性并不改变,这便是深拷贝的一个简单例子。
3.总结
- 这是我学习时的笔记,如有错误的地方恳请大家指正。┗( ▔, ▔ )┛
- 原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效。