一:原型模式的定义?
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
简单地讲:给定一个原型对象来指明所要创建的对象的类型,然后用拷贝这个原型对象的方法来创建出更多的同类型对象。
二:JAVA中原型模式的实现?
在JAVA里,通过克隆(Clone())方法来实现原型模式。
任何类,要想支持克隆,必须实现一个接口 Cloneable,该接口中有clone()方法,可以在类中重写自定义的克隆方法。
克隆的实现方法有三种:
(1)浅拷贝:浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对直接引用进行拷贝,没有对直接引用指向的对象进行拷贝。
(2)深拷贝:深拷贝是指在拷贝对象时,不仅把基本数据类型的变量会重新复制一份,同时会对引用指向的对象进行拷贝。
(3)完全拷贝:在包括上面两者共同点的基础上把对象间接引用的对象也进行拷贝。这是最彻底的一种拷贝。通常先使对象序列化,实现Serializable接口 然后将对象写进二进制流里 再从二进制流里读出新对象。
克隆的特点:
(1)克隆的对象与原对象并不是同一个对象,分别占用不同的堆空间 x.clone()!=x
(2)克隆的对象与原对象的类型一样 x.clone().getClass()==x.clone().getClass()
(3)克隆对象不会调用构造函数
三: 原型模式的优点?
<1> 提高性能
使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
<2>简化对象的创建
因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但以使系统的整体性能提高很多而且可以简化创建过程,
<3> 逃避构造函数的约束。
使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。
四: 代码演示。
<浅拷贝>
创建Address 对象类 ,重写clone()方法
package com.prototype;
public class Address implements Cloneable{
private String location;
public Address(String location){
this.location=location;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Address clone(){
Address a=null;
try {
a=(Address)super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return a;
}
}
测试类:
package com.prototype;
/**
* 浅拷贝测试类
*
* @author vean
*
*/
public class ShallowCopying {
public static void main(String[] args) {
Address address=new Address("北京"); //新建一个对象 ,这个对象用作被克隆的原型
Address cloneAddress= address.clone(); // 调用原型对象的克隆方法,克隆出一个对象
System.out.println("提供的原型城市名称: "+address.getLocation());
System.out.println("克隆的的城市名称: "+cloneAddress.getLocation());
System.out.println("两个城市对象"+(address == cloneAddress?"相同":"不同")); //测试被可伶的对象与原对象是否是同一个对象
}
}
输出结果:
<深拷贝>
创建Student类 ,为其添加地址address成员对象,重写clone()方法
package com.prototype;
public class Student implements Cloneable{
private String name;
Address address;
public Student(String name, Address address) {
super();
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Student clone(){
Student s=null;
try {
s=(Student)super.clone();
s.address=(Address)address.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return s;
}
}
测试类:
package com.prototype;
/**
* 深拷贝测试类
*
* @author vean
*
*/
public class DeepCoping {
public static void main(String[] args) {
Address address = new Address("北京");
Student s = new Student("张三", address);
Student sclone = (Student) s.clone();
System.out.println("学生姓名:" + s.getName() + " 克隆学生姓名:" + sclone.getName());
System.out.println("学生地址:" + s.address.getLocation() + " 克隆学生地址:" + sclone.address.getLocation());
System.out.println("两个学生对象"+(s == sclone?"相同":"不同")); //测试被可伶的对象与原对象是否是同一个对象
System.out.println("修改被克隆学生姓名为李四,地址为四川,");
s.setName("李四");
s.address.setLocation("四川");
System.out.println("学生姓名:" + s.getName() + " 克隆学生姓名:" + sclone.getName());
System.out.println("学生地址:" + s.address.getLocation() + " 克隆学生地址:" + sclone.address.getLocation());
// 浅复制只复制值类型的变量和对对象的引用
// 深复制不仅复制值类型的变量,把原对象引用的对象也进行复制.
}
}
运行结果:
<完全拷贝>
新建Author类,实现 Serializable 接口 创建absoluteClone()方法 这里要记住该对象引用的对象 Address类也需要实现 Serializable 接口
package com.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
public class Author implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2719717328965672807L;
private String name;
Address address;
public Author(String name, Address address) {
super();
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
// 使用序列化技术实现完全拷贝
public Author absoluteClone() throws IOException, ClassNotFoundException, OptionalDataException
{
// 将对象写入流中
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
// 将对象从流中取出
ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Author) ois.readObject();
}
}
测试类:
package com.prototype;
import java.io.IOException;
import java.io.OptionalDataException;
/**
* 完全拷贝测试类
*
* @author vean
*
*/
public class AbsoluteCopying {
public static void main(String[] args) throws OptionalDataException, ClassNotFoundException, IOException {
Address address = new Address("南京");
Author author = new Author("老王", address);
Author cloneAuthor = author.absoluteClone();
System.out.println("原作者作者姓名: " + author.getName() + " 住址: " + author.getAddress().getLocation());
System.out.println("克隆作者姓名: " + cloneAuthor.getName() + " 住址: " + cloneAuthor.getAddress().getLocation());
System.out.println("修改原作者姓名为 隔壁老王,住址为 北京");
author.setName("隔壁老王");
author.setAddress(new Address("北京"));
System.out.println("原作者作者姓名: " + author.getName() + " 住址: " + author.getAddress().getLocation());
System.out.println("克隆作者姓名: " + cloneAuthor.getName() + " 住址: " + cloneAuthor.getAddress().getLocation());
}
}
运行结果:
由此可见 完全拷贝将某对对象直接引用对象,包括引用对象引用的对象都重新复制,不需要实现Cloneable接口,重写Clone()方法,较为简单