今天介绍原型模式,也是最后一个建造型设计模式
定义:通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的方法来创建出更多的新对象。
定义很简单,就是通过实例制定种类,通过拷贝创建对象,该模式适用于以下场景1,对象的创建十分复杂。2在运行的过程中并不知道对象的具体类型,可以使用原型模式来
创建一个相同类型的对象出来。
在Java中,实现原型模式很简单,即实现cloneable接口,然后使用object类提供的clone方法进行拷贝,而拷贝又分为浅拷贝和深度拷贝下面我们来用代码实现浅拷贝
public class Student implements Cloneable {
public StudentMessage studentMessage;
public void setStudentMessage (StudentMessage studentMessage){
this.studentMessage=studentMessage;
}
@Override
public Student clone() {
Student student= null;
try {
student = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
}
public class StudentMessage{
String name;
String ID;
public StudentMessage(String name, String ID) {
this.name = name;
this.ID = ID;
}
}
测试类
public class Test {
public static void main(String[] args) {
Student phoneA=new Student();
phoneA.setStudentMessage(new StudentMessage("zhangsan","1234"));
Student phoneB = phoneA.clone();
System.out.print("phoneA:"+phoneA.toString());
System.out.print(" phoneB:"+phoneB.toString());
System.out.print(" StudentMessageA:"+phoneA.studentMessage.toString());
System.out.print(" StudentMessageB:"+phoneB.studentMessage.toString());
}
}
结果输出:
上面即为最简单的原型模式的实现,其中浅拷贝的基本变量都会重新创建,而引用类型,指向还是原来的对象所指向,上面例子中的student还是指向原来的。值得注意的是,运用clone()方法创建出来的对象的构造方法并不会执行。
深拷贝
深拷贝会使引用类型都重新创建,在java中有两种写法,一种为需要克隆对象所使用的所有引用类型都实现cloneable接口,然后重写object类提供的clone方法进行拷贝。
public class StudentMessage implements Cloneable{
String name;
String ID;
public StudentMessage(String name, String ID) {
this.name = name;
this.ID = ID;
}
@Override
protected StudentMessage clone() throws CloneNotSupportedException {
return (StudentMessage) super.clone();
}
}
public class Student implements Cloneable {
public StudentMessage studentMessage;
public void setStudentMessage (StudentMessage studentMessage){
this.studentMessage=studentMessage;
}
@Override
public Student clone() {
Student student= null;
try {
student = (Student) super.clone();
studentMessage = student.studentMessage.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
}
测试:
public class Test {
public static void main(String[] args) {
Student phoneA=new Student();
phoneA.setStudentMessage(new StudentMessage("zhangsan","1234"));
Student phoneB = phoneA.clone();
System.out.print("phoneA:"+phoneA.toString());
System.out.print(" phoneB:"+phoneB.toString());
System.out.print(" StudentMessageA:"+phoneA.studentMessage.toString());
System.out.print(" StudentMessageB:"+phoneB.studentMessage.toString());
}
}
输出:
phoneA:com.wujie.demo.clone.Student@266474c2
phoneB:com.wujie.demo.clone.Student@6f94fa3e
StudentMessageA:com.wujie.demo.clone.StudentMessage@5e481248
StudentMessageB:com.wujie.demo.clone.StudentMessage@66d3c617
我们可以看到,其中引用类型被重新创建了,但是,假如我们引用的类型里,又有新的引用类似的时候,用这种方法完成深度拷贝会无比的麻烦,这个时候我们利用序列化进行拷贝
public class StudentMessage implements Serializable{
String name;
String ID;
public StudentMessage(String name, String ID) {
this.name = name;
this.ID = ID;
}
}
public class Student implements Serializable {
public StudentMessage studentMessage;
public void setStudentMessage (StudentMessage studentMessage){
this.studentMessage=studentMessage;
}
@Override
public Student clone() {
Student student=null;
try {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bais=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
student = (Student) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
return student;
}
}
我们注意到,所有的引用类都要继承serializable接口才可以序列化
测试:
public class Test {
public static void main(String[] args) {
Student phoneA=new Student();
phoneA.setStudentMessage(new StudentMessage("zhangsan","1234"));
Student phoneB = phoneA.clone();
System.out.print("phoneA:"+phoneA.toString());
System.out.print(" phoneB:"+phoneB.toString());
System.out.print(" StudentMessageA:"+phoneA.studentMessage.toString());
System.out.print(" StudentMessageB:"+phoneB.studentMessage.toString());
}
}
输出:
phoneA:com.wujie.demo.clone.Student@355da254
phoneB:com.wujie.demo.clone.Student@12edcd21
StudentMessageA:com.wujie.demo.clone.StudentMessage@4dc63996
StudentMessageB:com.wujie.demo.clone.StudentMessage@34c45dca
可以看到,利用序列化的方式可以相对简单的完成深度克隆,序列化就是将对象写进流的过程,写进流的过程会对原有对象进行拷贝克隆
到此就将5种创建型模式一一介绍完毕。