赞
踩
原型模式属于对象的创建模式。。原型模式允许你通过复制现有的实例来创建新的实例。
这个模式的重点在于,客户端的代码在不知道要实例化何种特定类的情况下,可以制造出新的实例。在java中,一般使用clone()的方法,或者序列化。
在java中,由于Object类中有一个clone()方法,所以要使用原型模式非常简单,只要实现Cloneable的接口就可以了。
Java语言提供的Cloneable接口只起一个作用,就是在运行时期通知Java虚拟机可以安全地在这个类上使用clone()方法。通过调用这个clone()方法可以得到一个对象的复制。由于Object类本身并不实现Cloneable接口,因此如果所考虑的类没有实现Cloneable接口时,调用clone()方法会抛出CloneNotSupportedException异常。
具体代码如下:
public class Student implements Cloneable ,Serializable{
private String name;
private transient int age;
private Book book;
//浅克隆
public Student clone(){
Student stu = null;
try {
stu = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
//深克隆
public Student deepClone() throws Exception {
Student stu = null;
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bo);
oos.writeObject(this);
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
stu = (Student) oi.readObject();
return stu;
}
public Student(String name, int age, Book book) {
this.name = name;
this.age = age;
this.book = book;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
}
public class Book implements Serializable{
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Client {
public static void main(String[] args){
Book book = new Book("Chinese");
Student s = new Student("Tom",12,book);
Student s1 = s.clone();
System.out.println(s==s1);
System.out.println(s.getClass()==s1.getClass());
System.out.println(s.getBook()==s1.getBook());
System.out.println("------------------------");
try {
Student s2 = s.deepClone();
System.out.println(s==s2);
System.out.println(s.getClass()==s2.getClass());
System.out.println(s.getBook()==s2.getBook());
System.out.println("-------------------");
System.out.println("s.age:"+s.getAge()+" s2.age:"+s2.getAge());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下:
在例子中可以看到,使用Clone()方法,我们可以很容易的复制一个新的实例。
但是,这样的复制,使用的是浅克隆,那么什么是浅克隆哪?
浅克隆:
只负责克隆按值传递的数据(比如基本数据类型、String类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。
也就是说如果被克隆的对象中,有对其他对象的引用,那么就只复制那个对象的引用,而不是重新复制一个新的对象。
在上面的例子中,Student对象中具有对Book的引用,那么在使用浅克隆时(使用Clone()方法),复制的s1的book和原来的book是同一个对象,所以s.getBook() ==s1.getBook() 返回 true。
深克隆:
除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。
深克隆的方法有,反序列化,重写Clone()方法等。在上述例子中,就使用了序列化和反序列化的手段。由此,s.getBook() ==s1.getBook() 返回 false。
利用序列化实现深度克隆
把对象写到流里的过程是序列化(Serialization)过程;而把对象从流中读出来的过程则叫反序列化(Deserialization)过程。应当指出的是,写到流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。
在序列化一个对象时,应该先实现Serializable接口,然后把对象(实际是对象的拷贝)写到流里面,然后再从流里面反序列化出来,这样就重新创建了一个对象。
使用这个方法有一个前提,那就是要克隆的对象所引用的所有对象都应该是可序列化的,那么如果遇到不可序列化的对象时应该怎么办哪?
这时就要用到transient关键字了(注意:transient只能修饰变量),被transient修饰的变量在序列化时不会被序列化。在上述的例子中,Student的age变量使用了transient关键字修饰,所以我们可以看到s.getAge()的值为12,而s2.getAge()的值为0(int类型默认值为0)。
优点:
1、向客户隐藏制造新实例的复杂性。
2、提供让客户能够产生未知类型对象的选项。
3、在某些环境下,复制对象比创建对象更加有效。
缺点:
1、对象的复制有时相当的复杂。特别是当一个类引用不支持序列化的间接对象,或者引用含有循环结构的时候。
用途:
1、在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。