设计模式--创建型--原型模式
原型模式
概述
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
结构
原型模式包含如下角色
- 抽象原型类:规定了具体原型对象必须实现的clone()方法
- 具体原型类:实现抽象原型的clone()方法,它是可被复制的对象。
- 访问类:使用具体原型类中的clone()方法来复制新的对象。
实现
原型模式的克隆分为浅克隆和深克隆。
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不在指向原有对象地址。
Java中的Object类中提供了clone()方法来实现浅克隆。
java
/**
* 具体的原型类实现Cloneable接口 这里用Cloneable接口来当做抽象原型类
*/
public class RealizeType implements Cloneable{
public RealizeType(){
System.out.println("使用构造器创建具体的原型对象");
};
/**
* 重写clone()方法
* @return RealizeType
*/
@Override
public RealizeType clone() throws CloneNotSupportedException{
System.out.println("clone具体原型对象成功");
return (RealizeType) super.clone();
}
}
java
public class Test01 {
public static void main(String[] args) throws CloneNotSupportedException {
// 创建一个原型对象
RealizeType realizeType = new RealizeType();
// 调用RealizeType中的clone方法进行对象的克隆
RealizeType clone = realizeType.clone();
System.out.println("原型对象和克隆对象是否是同一个对象?"+ (clone == realizeType));
}
}
结果
案例
用原型模式生成"三好学生"奖状
奖状除了获奖人信息不同,其他都相同,可以使用原型模式复制多个"三好学生奖状",然后修改学生信息即可
代码
java
public class Citation implements Cloneable{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
@Override
public Citation clone() throws CloneNotSupportedException{
return (Citation) super.clone();
}
public void info(){
System.out.println(name + "同学的奖状");
}
}
java
public class Test01 {
public static void main(String[] args) throws CloneNotSupportedException {
// 创建奖状原型
Citation citation = new Citation();
citation.setName("张三");
Citation clone = citation.clone();
clone.setName("李四");
citation.info();
clone.info();
}
}
结果
- 这里虽然是浅拷贝但是name属性没有改变,是因为name是String类型,如果是引用类型并且还是浅拷贝,那么原型对象中的name是改变的,下面是深、浅克隆演示。
使用场景
- 对象的创建非常复杂,可以使用原型模式快捷的创建对象
- 性能和安全的要求比较高
扩展(深\浅克隆)
这里将上面的name属性放到一个student对象中,而Citation类中的Student属性就是引用属性
浅克隆演示:
java
public class Citation implements Cloneable{
private Student stu;
public Student getStu(){
return stu;
}
public void setStu(Student stu){
this.stu = stu;
}
@Override
public Citation clone() throws CloneNotSupportedException{
return (Citation) super.clone();
}
public void info(){
System.out.println(stu.getName() + "同学的奖状");
}
}
java
public class Student {
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
java
public class Test01 {
public static void main(String[] args) throws CloneNotSupportedException {
// 创建奖状原型
Citation citation = new Citation();
// 创建学生对象
Student student = new Student();
student.setName("张三");
citation.setStu(student);
citation.info();
// 克隆
Citation clone = citation.clone();
// 重新设置学生姓名
clone.getStu().setName("李四");
citation.info();
clone.info();
}
}
结果:
说明:原型对象和克隆出来的对象中的student对象是同一个对象,修改其中一个,另一个的值也会改变。
这就是浅克隆的效果,对具体原型类中的引用数据类型进行引用的复制。
使用深克隆(利用对象流)
克隆时先将原型对象写入文件中,再读取。
java
public class Citation implements Cloneable, Serializable {
private Student stu;
public Student getStu(){
return stu;
}
public void setStu(Student stu){
this.stu = stu;
}
@Override
public Citation clone() throws CloneNotSupportedException{
return (Citation) super.clone();
}
public void info(){
System.out.println(stu.getName() + "同学的奖状");
}
}
java
public class Student implements Serializable {
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
java
public class Test02 {
public static void main(String[] args) throws Exception {
// 创建奖状原型
Citation citation = new Citation();
// 创建学生对象
Student student = new Student();
student.setName("张三");
citation.setStu(student);
citation.info();
// 创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e:/a.txt"));
// 写对象
oos.writeObject(citation);
// 释放
oos.close();
// 创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:/a.txt"));
// 读取对象
Citation citation1 = (Citation) ois.readObject();
ois.close();
citation1.getStu().setName("李四");
citation.info();
citation1.info();
}
}