Specify the kinds of objects to create using a prototypical instance , and create new objects by copying this prototype.
一言蔽之——“创建和原型一样的对象实例”(“复制-粘贴”) 通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对
象的办法创建出更多同类型的对象。这就是选型模式的用意。
原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通
过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对
象,而无须再去通过new来创建。
在这之前,首先需要理解一下深复制和浅复制的概念
浅复制: 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅
仅复制所考虑的对象,而不复制它所引用的对象。
深复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复
制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
Java本身有自己的clone()方法,一般来说:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
如何使用clone()方法呢?
①在派生类中实现Cloneable接口。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
首先举一个浅复制的例子:
类对象的具体类:
class Professor
{
String name;
int age;
Professor(String name,int age)
{
this.name=name;
this.age=age;
}
}
需要复制的类:
public class Student implements Cloneable
{
String name;// 常量对象。
int age;
Professor p;// 学生1和学生2的引用值都是一样的。
Student(String name,int age,Professor p)
{
this.name=name;
this.age=age;
this.p=p;
}
public Object clone()
{
Student o=null;
try
{
o=(Student)super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
o.p=(Professor)p.clone();
return o;
}
}
在测试类中
创建了一个student对象,然后通过clone复制。不过需要注意的是,这里的引用对象并没有复制,修改原对象中的teacher对象的属
性,会发生两个student对象都会发生改变。为了能够做到引用对象的复制,必须要进行深复制。
深复制:
方法1:将类对象的类也继承cloneable接口,实现可复制。
class Professor implements Cloneable
{
String name;
int age;
Professor(String name,int age)
{
this.name=name;
this.age=age;
}
public Object clone()
{
Object o=null;
try
{
o=super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
return o;
}
}
public class Student implements Cloneable
{
String name;
int age;
Professor p;
Student(String name,int age,Professor p)
{
this.name=name;
this.age=age;
this.p=p;
}
public Object clone()
{
Student o=null;
try
{
o=(Student)super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
//对引用的对象也进行复制
o.p=(Professor)p.clone();
return o;
}
}
方法2:利用串行化来进行深复制
主要是为了避免重写比较复杂对象的深复制的clone()方法,也可以程序实现断点续传等等功能。把对象写到流里的过程是串
行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来
的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。
应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java
咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流
里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
public Object deepClone()
{
//将对象写到流里
ByteArrayOutoutStream bo=new ByteArrayOutputStream();
ObjectOutputStream oo=new ObjectOutputStream(bo);
oo.writeObject(this);
//从流里读出来
ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi=new ObjectInputStream(bi);
return(oi.readObject());
}
这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象或属性可否设
成transient,从而将之排除在复制过程之外。
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久
性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
类对象的类:
class Teacher implements Serializable {
private int te_id;
private transient String te_String;
public Teacher(int id, String String) {
this.te_id = id;
this.te_String = String;
}
public int getTe_id() {
return te_id;
}
public String getTe_String() {
return te_String;
}
public void setTe_id(int te_id) {
this.te_id = te_id;
}
public void setTe_String(String te_String) {
this.te_String = te_String;
}
}
学生类:
public class Student implements Serializable {
private int stu_id;
private transient String stu_name;
private Teacher teacher;
public Student(int id, String name, Teacher t) {
stu_id = id;
stu_name = name;
teacher = t;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public int getStu_id() {
return stu_id;
}
public void setStu_id(int stu_id) {
this.stu_id = stu_id;
}
public String getStu_name() {
return stu_name;
}
public void setStu_name(String stu_name) {
this.stu_name = stu_name;
}
public Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);// 从流里读出来
oo.close();
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
oi.close();
return (oi.readObject());
}
public static void main(String[] args) throws IOException,
ClassNotFoundException {
Teacher t1 = new Teacher(1, "A");
Student s1 = new Student(1, "b", t1);
Student s2 = (Student) s1.deepClone();
s2.setStu_name("b");
System.out.println(s2.getTeacher().getTe_id());
}
}