传统方法要创建一个新对象B与另一个对象A的属性值完全一致,就是重新获取A的属性值,然后通过new进行实例化,这种创建对象的方法复杂且效率低,而且需要重新初始化对象,不能动态的获取A的运行时状态数据。
针对传统方法的问题,提出了原型模式,原型模式是将A对象(原型对象),通过克隆的方式实现对其拷贝,然后产生一个新对象B,这个B对象与A对象的属性值完全一致,原型模式拷贝对象,效率高,操作简单,能捕捉原型对象的运行时状态数据。
原型模式就像克隆羊多莉一样,通过一只原型羊克隆出另一个完全一样的羊,本文以克隆羊对象为案例,提出传统解决方案及原型模式的解决方案,并对原型模式中的浅拷贝和深拷贝进行剖析。
原型模式就是拷贝对象。
传统方式实现Sheep原型对象的复制示意图如下:
//原型类
public class Sheep {
private String name;
private int age;
private String color;
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
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 String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
}
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//原型对象
Sheep sheep = new Sheep("tom", 1, "白色");
//创建与原型对象属性一样的新对象
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
//....
}
}
传统方法编写复杂且效率低。
原型模式只需要实现Cloneable接口,然后重写Object类中的clone方法,即可通过clone方法实现原型对象的拷贝。
示例代码如下:
//实现Cloneable接口
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
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 String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//实现clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
}
}
public class Client {
public static void main(String[] args) {
// 原型对象
Sheep sheep = new Sheep("tom", 1, "白色");
//克隆对象
Sheep sheep2 = (Sheep)sheep.clone(); //克隆
Sheep sheep3 = (Sheep)sheep.clone(); //克隆
Sheep sheep4 = (Sheep)sheep.clone(); //克隆
Sheep sheep5 = (Sheep)sheep.clone(); //克隆
}
}
上面的案例,虽然重写Object中的clone方法,但仅仅采用父类的实现,这种方式只是实现了浅拷贝,即如果拷贝的原型对象中存在引用类型,那么浅拷贝是只拷贝了引用类型的引用地址,并未真正拷贝一份空间。
具体一点的例子,就比如你觉得邻居家的房子盖的很漂亮,你也想拥有像邻居家一样的房子,如果你采用浅拷贝的方式,那当你向外人介绍的时候,只能指着邻居家房子说:“你瞧那个房子,就是我的房子”,也就是你和邻居家共同拥有一个同一个房子,如果你邻居要装修为其他样式,那你也跟着变。但如果你采用深拷贝的方式,那就是你按照邻居的房子样式,自己盖一个和邻居家一模一样的房子,当你再向外人介绍的时候,你就会指着自己的房子说:“你瞧这个房子,就是我的房子”,如果你邻居要把他的房子装修为其他样式,那丝毫影响不了你的房子。
浅拷贝的只需要将原型类实现Cloneable 接口,然后将重写的clone方法直接采用父类的实现即可。
如A类中有一个B类引用,如果要通过改写clone方法实现对A类进行深拷贝,代码示例如下:
public class A implements Cloneable{
public String Info;
public B b;
public A(String info, B b) {
Info = info;
this.b = b;
}
@Override
protected Object clone() throws CloneNotSupportedException {
A clone = (A)super.clone();
clone.b= (B) b.clone();//对引用类进行深拷贝
return clone;
}
}
public class B implements Cloneable{
public String Info;
public B(String info) {
Info = info;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class test {
public static void main(String[] args) throws CloneNotSupportedException {
A a = new A("原型类", new B("原型类中的引用类"));
A a1 = (A) a.clone();
System.out.println(a.b.Info);
System.out.println(a1.b.Info);
System.out.println(a.b.hashCode());
System.out.println(a1.b.hashCode());
}
}
输出结果:
与上一个案例一样,若A类中有一个B类引用,如果要通过序列化实现对A类进行深拷贝,代码示例如下:
//A类实现序列化
public class A implements Serializable{
public String Info;
public B b;
public A(String info, B b) {
Info = info;
this.b = b;
}
//通过序列化实现深拷贝
public Object deepClone() {
A deepCopy=null;
ByteArrayOutputStream bos=null;
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
deepCopy = (A) ois.readObject();
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
finally {
//关闭流
try {
bos.close();
oos.close();
ois.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
return deepCopy;
}
}
public class B implements Serializable{
public String Info;
public B(String info) {
Info = info;
}
}
public class test {
public static void main(String[] args) throws CloneNotSupportedException {
A a = new A("原型类", new B("原型类中的引用类"));
A a1 = (A) a.deepClone();
System.out.println(a.b.Info);
System.out.println(a1.b.Info);
System.out.println(a.b.hashCode());
System.out.println(a1.b.hashCode());
}
}