https://www.bilibili.com/video/av29579073/?p=8
https://www.bilibili.com/video/av29579073/?p=9
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
通常我们可以使用new的方式来创建一个新的对象。但是这种方式效率很低,如果我们需要克隆一个对象,那么完全可以使用原型模式来实现这个操作。
那么这篇博客我就介绍两种原型模式的实现方法,一种是通过Object的clone方法,一种是通过序列化的方法实现。
目录
1.Object的clone方法实现原型模式
以多利羊为例,原型模式中的类需要实现Cloneable接口。
public class Sheep implements Cloneable,Serializable { //1997,英国的克隆羊,多利!
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone(); //直接调用object对象的clone()方法!
return obj;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
public Sheep() {
}
}
具体的调用如下
public class Client {
public static void main(String[] args) throws Exception {
Date date = new Date(12312321331L);
Sheep s1 = new Sheep("少利",date);
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
date.setTime(23432432423L);
System.out.println(s1.getBirthday());
Sheep s2 = (Sheep) s1.clone();
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
}
}
注意,这个地方实际上是一个浅拷贝,学过C++的我们都应该清楚浅拷贝就是拷贝的对象拷贝了原对象中非基本数据类型的引用而不是地址空间,这样如果date的值改变了。那么多利和少利的birthday都会改变。所以为了解决这个问题,实际上在克隆少利时也应该为它的birthday进行克隆。
代码如下:
//测试深复制
public class Sheep2 implements Cloneable { //1997,英国的克隆羊,多利!
private String sname;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone(); //直接调用object对象的clone()方法!
//添加如下代码实现深复制(deep Clone)
Sheep2 s = (Sheep2) obj;
s.birthday = (Date) this.birthday.clone(); //把属性也进行克隆!
return obj;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Sheep2(String sname, Date birthday) {
super();
this.sname = sname;
this.birthday = birthday;
}
public Sheep2() {
}
}
2.通过序列化实现原型模式
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
可以将对象写入到IO流中进行读取,这样也是实现了克隆,序列化的对象需要实现Serializable接口。
代码与测试如下:
public class Client3 {
public static void main(String[] args) throws CloneNotSupportedException, Exception {
Date date = new Date(12312321331L);
Sheep s1 = new Sheep("少利",date);
System.out.println(s1);
System.out.println(s1.getSname());
System.out.println(s1.getBirthday());
// 使用序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(s1);//将s1对象写入到bos流中
byte[] bytes = bos.toByteArray();//获取这个对象的字节数组
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);//读取这个字节数组
ObjectInputStream ois = new ObjectInputStream(bis);//获取一个对象读取输入流
Sheep s2 = (Sheep) ois.readObject(); //克隆好的对象!
System.out.println("修改原型对象的属性值");
date.setTime(23432432423L);
System.out.println(s1.getBirthday());
s2.setSname("多利");
System.out.println(s2);
System.out.println(s2.getSname());
System.out.println(s2.getBirthday());
}
}