一、什么是原型模式?
原型模式(Prototype Pattern)是一种创建型设计模式,它允许一个对象通过拷贝(克隆)现有的实例来创建新的对象,而不是通过传统的构造器创建新的实例。其核心是重写Object中的clone方法,调用该方法可以在内存中进行对象拷贝。这种模式的主要目的是为了提高性能和复用现有对象的状态。关键字就是Clone。
二、角色组成
原型接口(Prototype Interface):定义一个用于克隆自身的接口,通常包括一个 clone() 方法。
具体原型类(Concrete Prototype):实现原型接口的具体类,负责实际的克隆操作。这个类需要实现 clone() 方法,通常使用浅拷贝或深拷贝来复制自身。
客户端(Client):使用原型实例来创建新的对象。客户端调用原型对象的 clone() 方法来创建新的对象,而不是直接使用构造函数。
三、应用场景
创建大量相似对象:
如果需要创建大量相似的对象,并且这些对象的创建过程非常相似,那么可以考虑使用原型模式。例如,在图形界面程序中,经常需要创建多个具有相同外观和行为的控件,通过克隆一个已配置好的控件原型来创建新的控件可以大大减少初始化的工作量。
四、实现(浅克隆和深克隆)
浅克隆
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
实现:
public class Citationimplements Cloneable{
public Realizetype() {
System.out.println("具体的原型对象创建完成!");
}
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return (this.name);
}
public void show() {
System.out.println(name + "同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!");
}
/**
* 重写超级父类Object提供的clone()方法,实现浅克隆
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Citationclone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功!");
return (Realizetype) super.clone();
}
}
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Citation c1= new Realizetype();
Citation c2= r1.clone();
c1.setName("张三");
//复制奖状
Citation c2 = c1.clone();
//将奖状的名字修改李四
c2.setName("李四");
System.out.println("c1== c2?" + (c1== c2));
c1.show();
c2.show();
}
}
运行结果
张三同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
李四同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!
c1== c2?false
分析
name 是一个字符串变量,属于基本数据类型的封装类,因此在浅克隆时会复制其值而不是引用。
引用类型实例:
public class Student {
private String name;
private String address;
public Student(String name, String address) {
this.name = name;
this.address = address;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
public class Citation implements Cloneable{
private Student stu;
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
void show() {
System.out.println(stu.getName() + "同学:在2023学年第一学期中表现优秀,被评为三好学生。特发此状!");
}
@Override
public Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
测试类
public class CitationTest {
public static void main(String[] args) throws CloneNotSupportedException {
Citation c1 = new Citation();
Student stu = new Student("张三", "西安");
c1.setStu(stu);
//复制奖状
Citation c2 = c1.clone();
//获取c2奖状所属学生对象
Student stu1 = c2.getStu();
stu1.setName("李四");
//判断stu对象和stu1对象是否是同一个对象
System.out.println("stu和stu1是同一个对象?" + (stu == stu1));
c1.show();
c2.show();
}
}
分析
在这种情况下,如果修改了浅克隆后对象中的 Student ,原对象中的 Student 也会受到影响,因为它们指向的是同一个数组对象。这意味着浅克隆后的新对象和原对象会共享这些引用类型成员变量指向的对象。
深克隆
深克隆:指创建一个与原对象完全独立的新对象,引用类型属性不再指向原有对象地址。
实现
public class CitationTest1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Citation c1 = new Citation();
Student stu1 = new Student("张三","上海");
c1.setStu(stu1);
//创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
//将c1对象写出到文件中
oos.writeObject(c1);
oos.close();
//创建对象出入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
//读取对象
Citation c2 = (Citation) ois.readObject();
//从c2获取student对象
Student stu2 = c2.getStu();
stu2.setName("李四");
ois.close();
//判断stu对象和stu1对象是否是同一个对象
System.out.println("stu1和stu2是同一个对象?"+(stu1==stu2));
c1.show();
c2.show();
}
}
分析
在这个例子中,即使修改了深克隆后对象中的 Student,原对象中的 Student不会受到任何影响,因为它们指向的是不同的数组对象。总的来说,深克隆完全复制对象及其引用的对象,确保新旧对象之间没有依赖关系。。