设计模式之原型模式
介绍
原型模式就是一个原型对象,可以大量的克隆或者复制出与自己相同对象的模式,简称自我复制。是一种创建型模式。
优点
当构建一个对象比较复杂,且又大量使用到这种对象时,可以通过原型模式快速创建。
示例
如何让一个对象自我复制?
让实体类去实现java.lang.Cloneable并重写clone()方法。
public class Student implements Cloneable {
private String no;
private String name;
private String age;
public Student(String no, String name, String age) {
this.no = no;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override
protected Object clone() {
Student student=null;
try {
student=(Student) super.clone();
}catch (Exception e){
e.printStackTrace();
}
return student;
}
}
测试:
public class Main {
public static void main(String[] args) {
Student student=new Student("2222","张三","18");
Student student1=(Student) student.clone();
System.out.println(student1.toString());
}
}
结果:
.png)
浅拷贝
假如说我们现在又给Student新增了一个属性friend:
public class Student implements Cloneable {
private String no;
private String name;
private String age;
public Student friend;
public Student(String no, String name, String age,Student friend) {
this.no = no;
this.name = name;
this.age = age;
this.friend=friend;
}
@Override
public String toString() {
return "Student{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override
protected Object clone() {
Student student=null;
try {
student=(Student) super.clone();
}catch (Exception e){
e.printStackTrace();
}
return student;
}
}
再测试:
public class Main {
public static void main(String[] args) {
Student student2=new Student("1111","李四","20",null);
Student student=new Student("2222","张三","18",student2);
Student student1=(Student) student.clone();
System.out.println(student.toString()+student.friend.hashCode());
System.out.println(student1.toString()+student1.friend.hashCode());
}
}
结果:
.png)
从结果看出,两个“student”的“friend”指向了同一个对象。
如图所示:

这就是传说中的浅拷贝,即复制对象属性时,只复制值,当有一个引用型属性时也只会复制值,只不过此时值是被应用对象地址。所以复制出的对象属性也会指向同一个对象。
深拷贝
有浅拷贝自然有深拷贝,深拷贝复制的时候,会为引用属性开辟新的空间。
如图所示:

实现深拷贝的方式有两种:
1.重写clone()方法。
先来说说重写clone()方法。如果我们在重写的时候将引用对象也显示的调用clone()去拷贝一份,那么就会为它分配内存空间.
protected Object clone() {
Student student=null;
try {
student=(Student) super.clone();
student.friend=(Student) friend.clone();
}catch (Exception e){
e.printStackTrace();
}
return student;
}
虽然实现了深拷贝,但是存在一个问题:引用型成员变量也得去实现java.lang.Cloneable并重写clone()方法,当被引用的类型十分多的时候,想想那个代码量就让人头疼,所以不推荐这种方式。这种方式只适合简单的,引用较少的原型模式。
2.通过序列化。
序列化首先要实现Serializable接口。
class Student implements Serializable {
private String no;
private String name;
private String age;
public Student friend;
public Student(String no, String name, String age,Student friend) {
this.no = no;
this.name = name;
this.age = age;
this.friend=friend;
}
@Override
public String toString() {
return "Student{" +
"no='" + no + '\'' +
", name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
public Student objClone(){
Student student=null;
ByteArrayInputStream bis=null;
ByteArrayOutputStream bos=null;
ObjectInputStream ois=null;
ObjectOutputStream oos=null;
try {
//序列化
bos=new ByteArrayOutputStream();
oos=new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis=new ByteArrayInputStream(bos.toByteArray());
ois=new ObjectInputStream(bis);
student=(Student) ois.readObject();
}catch (Exception e){
e.printStackTrace();
}
return student;
}
}

浙公网安备 33010602011771号