1.简单介绍
- 通过new产生一个对象需要非常繁琐的数据准备,或者访问权限,则可以使用原型模式;
- 主要运用Java的克隆技术,以某个对象为原型,复制新对象;
- 克隆创建对象,类似于new,新创建的对象属性采用默认值,但是克隆出来的对象属性值完全和原型对象相同,而且克隆出的新对象改变不会影响原型对象,这样就只需要对克隆模型进行修改就可以了;
- 原型模型的实现:
Cloneable接口和clone方法;
- 如果对象使用new创建的时候比较复杂,就可以直接使用克隆创建对象;
2. 浅克隆
克隆的对象:
//这里实现浅克隆,原型模式需要克隆,
public class Computer implements Cloneable {
private String brand;
private BuyDate buytime;
public Computer(String brand, BuyDate buytime) {
this.brand = brand;
this.buytime = buytime;
}
public BuyDate getBuytime() {
return buytime;
}
public void setBuytime(BuyDate buytime) {
this.buytime = buytime;
}
//这里定义一个创建方法;
public String getBrand() {
return brand;
}
//这里只定义一个get方法,因为我也只取一个值;
public void setBrand(String brand) {
this.brand = brand;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
return obj;
}
}
class BuyDate{
private String time;
public BuyDate(String time) {
this.time = time;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
@Override
public String toString() {
return "BuyDate{" +
"time='" + time + '\'' +
'}';
}
}
测试类:
class Test{
public static void main(String[] args) {
BuyDate b = new BuyDate("2020");
try {
//创建对象;
Computer com = new Computer("联想",b );
//克隆对象,本来返回一个Object,但是后面需要用到Computer类中的方法,所以将其转换为这个;
Computer clone = (Computer) com.clone();
//对对象值进行修改;看克隆到的值是什么;
com.setBrand("华硕");
//这里直接对对象地址进行修改;
com.getBuytime().setTime("2017");
System.out.println(com.getBrand());
System.out.println("原始对象的商标:"+com.getBrand());
System.out.println(com.getBuytime());
System.out.println("拷贝对象的商标:"+clone.getBrand());
System.out.println(clone.getBuytime());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
测试结果:
从上面的结果可以看出来,这个浅克隆,在使用的时候调用的对象地址还是一样的;因为修改克隆后的BuyDate之后,原对象的也被修改了;就类似于下图;也就是说它们指向的地址是一样的,无论谁对其中的值进行修改,两个对象取到的值都会被改掉;
这里可能有人会对那个String类型的Brand为什么没有变化保持疑问,我一开始也没想到,后面仔细一想,String这个是没法改的,它的底层是一个final类型的数组,所以每次修改其实都是重新创建,重新创建地址自然就不一样了,这样想就知道为什么两个类型会不一致了;
3.深克隆
//这里实现浅克隆,原型模式需要克隆,
public class Computer implements Cloneable {
private String brand;
private BuyDate buytime;
public Computer(String brand, BuyDate buytime) {
this.brand = brand;
this.buytime = buytime;
}
public BuyDate getBuytime() {
return buytime;
}
public void setBuytime(BuyDate buytime) {
this.buytime = buytime;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Computer computer = (Computer) super.clone();
//在赋值的时候强转一下就可以了,右边其实是BuyDate类型;
computer.buytime=(BuyDate) this.buytime.clone();
return computer;
}
}
//想要这个对象属性能够克隆,必须要实现Cloneable接口;和clone方法;
class BuyDate implements Cloneable{
private String time;
public BuyDate(String time) {
this.time = time;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "BuyDate{" +
"time='" + time + '\'' +
'}';
}
}
这里需要注意的点,就是,如果需要将某些属性进行深克隆,这些属性如果是某些类的对象,那么就需要将这些类实现Cloneable接口,同时还要实现Object的clone的方法;最重要的是需要对什么属性进行深克隆,那么那个属性就要在重写克隆方法里面重新调用一下;
这里的测试类使用的就是上次的一样的测试类;
测试结果:
使用序列化和反序列化也可以实现深克隆;