原型模式
1.介绍
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
原型模式包含如下角色:
- 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
2.实现
原型模式的克隆分为浅克隆和深克隆。
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原 有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
浅克隆实现
Java中的Object类中提供了 clone() 方法来实现浅克隆。
Cloneable 接口是上面的类图中的抽 象原型类,
而实现了Cloneable接口的子实现类就是具体的原型类。
代码如下:
具体原型类
/**
* @author
* @date 2021/11/30 23:12
* 具体的原型类
*/
@Data
public class Realizetype implements Cloneable {
private Student student;
public Realizetype() {
System.out.println("具体原型类创建成功");
}
@Override
protected Realizetype clone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功!");
return (Realizetype) super.clone();
}
}
访问类(测试)
/**
* @author
* @date 2021/11/30 23:14
* 测试访问类
*/
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student("zhangsan",18);
Realizetype r1 = new Realizetype();
r1.setStudent(student);
Realizetype r2 = r1.clone();
System.out.println(r2==r1);//false
System.out.println(r1.getStudent()== r2.getStudent());//true
}
}
从打印结果来看,两个对象的成员属性student指向同一个地址,所以这种克隆方式属性浅克隆,
深克隆实现
序列化方式
注意:Realizetype和Student类都要实现Serializable接口
/**
* @author
* @date 2021/12/1 0:01
* 序列化方式实现深克隆
*/
public class SerializePrototypeTest {
public static void main(String[] args) throws Exception{
Student student = new Student("zs",22);
Realizetype r1 = new Realizetype();
r1.setStudent(student);
//将对象序列化 写入到磁盘
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\文件下载\\a.txt"));
oos.writeObject(r1);
oos.close();
//反序列化 读取对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\文件下载\\a.txt"));
Realizetype r2 = (Realizetype) ois.readObject();
ois.close();
System.out.println(r1==r2);
System.out.println(r1.getStudent()==r2.getStudent());//false 没有指向同一个对象
}
}
自定义clone方法实现
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable,Cloneable {
private String name;
private Integer age;
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
重写clone方法
/**
* @author
* @date 2021/11/30 23:12
* 具体的原型类
*/
@Data
public class Realizetype implements Cloneable , Serializable {
private Student student;
public Realizetype() {
System.out.println("具体原型类创建成功");
}
/**
* 自定义clone方法实现深克隆
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Realizetype clone() throws CloneNotSupportedException {
//先对对象进行浅克隆
Realizetype realizetype = (Realizetype) super.clone();
//将成员属性设置成一个新的对象 把原来的值set进去
//或者成员属性也重写重写clone方法 我们使用clone方法复制即可 但是如果很深的话就很烦(成员对象内部又有自己的非基本类型成员对象)
Student student = realizetype.getStudent();//目前执行同一个地址
Student newStu = student.clone();
realizetype.setStudent(newStu);
return realizetype;
}
}
测试
/**
* @author
* @date 2021/11/30 23:14
* 测试访问类
*/
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student("zhangsan",18);
Realizetype r1 = new Realizetype();
r1.setStudent(student);
Realizetype r2 = r1.clone();
System.out.println(r2==r1);//false
System.out.println(r1.getStudent()== r2.getStudent());//false
}
}
观察测试结果 发现实现了深拷贝
3.使用场景
-
对象的创建非常复杂,可以使用原型模式快捷的创建对象。
-
新对象和就对象的大部分属性都一样
-
性能和安全要求比较高。(无需新建对象再去一个一个set属性,clone是native方法,性能高)