原型模式
Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
使用场景
当一个系统应该独立于它的产品创建,构成和表示时,要用到原型模式,以及当要实例化的类在运行时刻指定时,例如通过动态装载,或者为了避免创建一个与产品类层次平行的工厂类层次时,或者当一个类的实例只能有几个不同状态组合中的一种时,建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
结构
实现
原型模式中的拷贝分为”浅拷贝”和”深拷贝”:
浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.
深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制.
我们先来看一下浅拷贝的实现
public class Prototype implements Cloneable {
private static final long serialVersionUID = 1L;
private String name;
private int num;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
@Override
protected Prototype clone(){
Prototype prototype = null;
try{
System.out.println("--------浅复制---------");
prototype = (Prototype)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return prototype;
}
}
客户端代码实现
public class Client {
public static void main(String[] args) {
Client client = new Client();
client.operation();
}
public void operation(){
Prototype cp = new Prototype();
cp.setName("original Name1");
cp.setNum(111);
Product product = new Product();
product.setTitle("title1");
cp.setProduct(product);
Prototype clonecp = (Prototype)cp.clone();
cp.setName("original Name2");
cp.setNum(222);
product.setTitle("title2");
System.out.println("cp name:"+cp.getName()+" clonecp name:"+clonecp.getName());
System.out.println("cp num:"+cp.getNum()+" clonecp num:"+clonecp.getNum());
System.out.println("cp product:"+cp.getProduct().getTitle()+" clonecp product:"+clonecp.getProduct().getTitle());
}
}
运行结果:
——–浅复制———
cp name:original Name2 clonecp name:original Name1
cp num:222 clonecp num:111
cp product:title2 clonecp product:title2
此处对象类型只是复制了引用,所以引用的对象改变了,结果也跟着改变,下面看一下深复制的实现
public class Prototype implements Cloneable,Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int num;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
private Product product;
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
/* @Override
protected Prototype clone(){
Prototype prototype = null;
try{
System.out.println("--------浅复制---------");
prototype = (Prototype)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return prototype;
}*/
@Override
protected Prototype clone(){
Prototype prototype = null;
ByteArrayOutputStream bos = null;
ByteArrayInputStream bis = null;
try{
System.out.println("--------深复制---------");
bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//读出二进制流产生的新对象
bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Prototype)ois.readObject();
}catch(Exception e){
e.printStackTrace();
}finally{
if(bos!=null&&bis!=null){
try {
bos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return prototype;
}
}
public class Product implements Serializable {
private String title;
public void setTitle(String title) {
this.title = title;
}
public String getTitle(){
return this.title;
}
}
客户端代码实现
public class Client {
public static void main(String[] args) {
Client client = new Client();
client.operation();
}
public void operation(){
Prototype cp = new Prototype();
cp.setName("original Name1");
cp.setNum(111);
Product product = new Product();
product.setTitle("title1");
cp.setProduct(product);
Prototype clonecp = (Prototype)cp.clone();
cp.setName("original Name2");
cp.setNum(222);
product.setTitle("title2");
System.out.println("cp name:"+cp.getName()+" clonecp name:"+clonecp.getName());
System.out.println("cp num:"+cp.getNum()+" clonecp num:"+clonecp.getNum());
System.out.println("cp product:"+cp.getProduct().getTitle()+" clonecp product:"+clonecp.getProduct().getTitle());
}
}
运行结果:
——–深复制———
cp name:original Name2 clonecp name:original Name1
cp num:222 clonecp num:111
cp product:title2 clonecp product:title1
可以看出深复制复制的很彻底,不仅复制了值类型的值,也复制了引用类型所引用的对象信息,而不仅仅是复制了引用