- 原型模式简介:也叫克隆模式
原型模式使用原型实例指定创建对象的种类,并且通过拷贝原型对象创建新的对象。
Prototype模式提供了一个通过已存在对象进行新对象创建的接口(clone), clone()实现和具体的语言
相关,在C++中通过拷贝构造函数实现。
原型模式实际上就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
在初始化的信息不发生变化的情况下,克隆是最好的办法,既隐藏了对象创建的细节,又大大提高了性能。
因为如果不用clone,每次new都需要执行一次构造函数,如果构造函数的执行时间很长,那么多次的执行
初始化操作就太低效了。
原型模式实现clone接口的时候必须使用深拷贝。
原型模式重点在从自身赋值自己创建新的类对象,隐藏创建的细节。
2. 什么叫浅克隆和深克隆
浅克隆:Address并没有被克隆而是克隆的引用
深克隆:Address对象也被克隆
3. 为什么要克隆?
大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗?
答案是:克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。那么我把这个对象的临时属性一个一个的赋值给我新new的对象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了clone是一个native方法,就是快啊,在底层实现的。
提个醒,我们常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。
而通过clone方法赋值的对象跟原来的对象时同时独立存在的。
4. 浅克隆
/**
* @author: 张瑛
* @date: 2019/10/29-14:43
*/
public class TestClone1 {
public static void main(String [] args){
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
stu2.setNumber(54321);
System.out.println("学生1:" + stu1.getNumber());
System.out.println("学生2:" + stu2.getNumber());
}
}
class Student implements Cloneable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
5.深克隆
问题代码:
package com.tencent.clone;
/**
* @author: 张瑛
* @date: 2019/10/29-14:47
*/
public class TestClone2 {
public static void main(String [] args){
Address addr = new Address();
addr.setAdd("杭州市");
Student2 stu2 = new Student2();
stu2.setNumber(123);
stu2.setAddr(addr);
Student2 stu3 = (Student2)stu2.clone();
System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());
addr.setAdd("安庆市");
System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());
//结果:
/**
* 学生1:123,地址:杭州市
* 学生2:123,地址:杭州市
* 学生1:123,地址:安庆市
* 学生2:123,地址:安庆市
* 就是说:addr.setAdd("安庆市")后,Address并没有被克隆而是克隆的引用
*/
}
}
class Address {
private String add;
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
}
class Student2 implements Cloneable{
private int number;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student2 stu = null;
try{
stu = (Student2)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
解决:
package com.tencent.clone;
/**
* @author: 张瑛
* @date: 2019/10/29-14:47
* Address类也实现 Cloneable接口
* 修改clone方法
*/
public class TestClone2 {
public static void main(String [] args){
Address addr = new Address();
addr.setAdd("杭州市");
Student2 stu2 = new Student2();
stu2.setNumber(123);
stu2.setAddr(addr);
Student2 stu3 = (Student2)stu2.clone();
System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());
addr.setAdd("安庆市");
System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());
//结果:
/**
* 学生1:123,地址:杭州市
* 学生2:123,地址:杭州市
* 学生1:123,地址:安庆市
* 学生2:123,地址:杭州市
*/
}
}
class Address implements Cloneable{
private String add;
public String getAdd() {
return add;
}
public void setAdd(String add) {
this.add = add;
}
@Override
public Object clone() {
Address addr = null;
try{
addr = (Address)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
}
class Student2 implements Cloneable{
private int number;
private Address addr;
public Address getAddr() {
return addr;
}
public void setAddr(Address addr) {
this.addr = addr;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() {
Student2 stu = null;
try{
stu = (Student2)super.clone(); //浅复制
stu.addr = (Address)addr.clone(); //深度复制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}