原型模式
黑马程序员:https://www.bilibili.com/video/BV1Np4y1z7BU?p=46
概述
用一个已经创建的实例作为原型,通过赋值该原型对象来创建一个和原型对象相同的新对象。
结构
原型模式包含的角色:
- 抽象原型类:规定了具体原型对象必须实现的clone()方法;
- 具体原型类:实现抽象原型类clone()方法,它是可以被复制的对象;
- 访问类:使用具体原型类中的clone()方法来复制新的对象。
分类
- 浅克隆:
创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址 - 深克隆
创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
Java中的Object类中提高了clone()
方法来实现浅克隆。Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。
浅克隆
应用场景
- 对象的创建非常复杂,可以使用原型模式快捷的创建对象;
- 性能和安全要求比较高。
引例
uml类图
Realizetype(具体原型类)
/*
具体原型类
*/
public class RealizeType implements Cloneable {
public RealizeType(){
System.out.println("具体原型对象创建完成!");
}
@Override
protected RealizeType clone() throws CloneNotSupportedException {
System.out.println("原型对象复制成功");
return (RealizeType) super.clone();
}
}
Client(访问类)
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
//创建一个原型类对象
RealizeType realizeType = new RealizeType();
//调用clone方法进行克隆
RealizeType clone = realizeType.clone();
//判断是否为同一个对象
System.out.println(realizeType==clone);// false 地址不同
}
}
测试结果
案例:用原型模式生成 “ 三好学生 ”奖状
同一学校的 “ 三好学生 ” 奖状出来获奖名字不同,其他都相同,可以使用原型模式来克隆多个奖状,然后修改奖状上的名字。
UML类图
代码实现
Citation(具体原型类)
/*
具体圆形类:奖状类
*/
public class Citation implements Cloneable{
//奖状上的学生姓名:name
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println(name+"获取'三好学生'奖状");
}
//克隆方法
@Override
protected Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
测试类(访问类)
/*
访问类
*/
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
//1.创建原型对象
Citation citation = new Citation();
//2.克隆奖状对象
Citation clone = citation.clone();
//3.设置奖状获得者名字
citation.setName("张三");
clone.setName("李四");
//4.调用show方法展示
clone.show();
citation.show();
}
}
测试结果
将上面的 “ 三好学生 ”奖状的案例中Citation类的name属性修改为Student类型的属性。
学生类
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
奖状类(具体原型类)
public class Citation implements Cloneable{
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public void show(){
System.out.println(student.getName()+"获取'三好学生'奖状");
}
@Override
protected Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
测试类(访问类)
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
//创建原型对象
Citation citation = new Citation();
//创建学生对象
Student student = new Student();
student.setName("张三");
citation.setStudent(student);
//创建克隆对象
Citation clone = citation.clone();
Student student1 = clone.getStudent();
student1.setName("李四");
System.out.println(student==student1);//true
//show方法展示
citation.show();
clone.show();
}
}
测试结果
说明
student和student1两个对象为同一个对象,就会产生修改name属性为“ 李四 ”时,显示效果同为李四,这就是浅克隆的效果。 这种情况就需要进行深克隆。
深克隆
对具体原型类中的引用的属性进行复制,这种情况需要使用深克隆,而进行深克隆需要使用对象流。
代码实现
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException, Exception {
//创建原型对象
Citation citation = new Citation();
//创建学生对象
Student student = new Student();
student.setName("张三");
citation.setStudent(student);
//创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("./Proto Pattern/b.txt"));
//写对象
oos.writeObject(citation);
//释放资源
oos.close();
//创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./Proto Pattern/b.txt"));
//读数据
Citation clone = (Citation) ois.readObject();
//释放资源
ois.close();
//设置获奖学生姓名
clone.getStudent().setName("李四");
//调用show方法展示
citation.show();
clone.show();
}
}
测试结果
注意:
- Student类和Citation类必须实现序列化(Serializable),否者会抛出异常(NotSerializableException)