原型模式可以理解为直接从已存在的对象中拷贝出一个新对象,在重新创建一个对象消耗较大,但又需要用到两个相互不影响的对象的时候才用到,这是它与单例模式的区别所在
原型模式中拷贝的方法有浅拷贝和深拷贝两种,浅拷贝因为直接引用对象,所以在修改拷贝出的对象的时候可能会影响到原对象,下面用购物商城的用户举个简单的例子
public class User{
public User(){
}
private String name;
private Image icon;
private ArrayList<String> address = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Image getIcon() {
return icon;
}
public void setIcon(Image icon) {
this.icon = icon;
}
public ArrayList<String> getAddress() {
return address;
}
public void setAddress(ArrayList<String> address) {
this.address = address;
}
}
浅拷贝
用户有用户名、头像、多个地址,如果要进行拷贝的话应该继承Cloneable接口并重写clone()函数,下面是浅拷贝的例子
@Override
protected User clone() {
try {
User user = (User)super.clone();
user.icon = this.icon;
user.name = this.name;
user.address = this.address;
return user;
} catch (CloneNotSupportedException e){
}
return null;
}
为什么称它为浅拷贝呢?因为在User类中我们使用的是引用型字段,即ArrayList,如果我们对拷贝对象的ArrayList中的对象进行修改,原对象也会受到影响,和拷贝对象中的地址保持一致,所以我们应该使用深拷贝,对引用型字段也进行拷贝,而不是简单地赋值
深拷贝
@Override
protected User clone() {
try {
User user = (User)super.clone();
user.icon = this.icon;
user.name = this.name;
user.address = (ArrayList<String>) this.address.clone(); //对引用型字段进行拷贝
return user;
} catch (CloneNotSupportedException e){
}
return null;
}
完整代码如下:
public class User implements Cloneable{
public User(){
}
private String name;
private Image icon;
private ArrayList<String> address = new ArrayList<>();
@Override
protected User clone() {
try {
User user = (User)super.clone();
user.icon = this.icon;
user.name = this.name;
user.address = (ArrayList<String>) this.address.clone();
return user;
} catch (CloneNotSupportedException e){
}
return null;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Image getIcon() {
return icon;
}
public void setIcon(Image icon) {
this.icon = icon;
}
public ArrayList<String> getAddress() {
return address;
}
public void setAddress(ArrayList<String> address) {
this.address = address;
}
}
保护性拷贝
保护性拷贝其实就是原型模式的一个实际应用,比如说上面举的商城的例子,如果我们在其他需要用到User对象的场景下不小心修改了User对象,那将使服务端和客户端的信息不一致,所以在这个场景下十分适合使用原型模式