定义
指通过拷贝原型来创建新的对象,不需要知道原型对象创建的细节,不调用构造函数
优点
- 原型模式性能比直接new一个对象性能高
- 简化创建过程
缺点
- 原型对象必须有克隆方法
- 对克隆复杂对象或克隆出的对象进行改造时,容易引入风险
代码实现
如下面的代码,我们通过原型模式来克隆一个User对象。
@Data
public class Address implements Cloneable{
private String province;
private String city;
private String street;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
@Data
public class User implements Cloneable{
private Long id;
private String username;
private String password;
private Integer age;
private Character gender;
private String hobby;
private Address address;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
下面我们调用下user的clone方法,看下clone出的对象值。
public class PrototypeMain {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
address.setProvince("浙江");
address.setCity("杭州");
User user = new User();
user.setId(1L);
user.setUsername("admin");
user.setPassword("123456");
user.setAddress(address);
System.out.println("proto: " + user);
User cloneUser = (User)user.clone();
System.out.println("clone: " + cloneUser);
//proto: User(id=1, username=admin, password=123456, age=null, gender=null, hobby=null, address=Address(province=浙江, city=杭州, street=null))
//clone: User(id=1, username=admin, password=123456, age=null, gender=null, hobby=null, address=Address(province=浙江, city=杭州, street=null))
}
}
如下面的结果所示,clone出来的结果与原来一致。注意,这里有个坑,我们改下cloneUser的Address的值,再看下原来的user的值
public class PrototypeMain {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
address.setProvince("浙江");
address.setCity("杭州");
User user = new User();
user.setId(1L);
user.setUsername("admin");
user.setPassword("123456");
user.setAddress(address);
User cloneUser = (User)user.clone();
cloneUser.getAddress().setProvince("江苏省");
cloneUser.getAddress().setCity("南京市");
System.out.println("modify proto: " + user);
//modify proto: User(id=1, username=admin, password=123456, age=null, gender=null, hobby=null, address=Address(province=江苏省, city=南京市, street=null))
}
}
从上面的结果可以看出,原来的user中的address值也被改变掉了。之所以出现这个问题是因为这里的clone实际上是浅copy,对于引用类型,copy的是地址,这里的cloneUser的address和user的address指向的是同一个address。所以改变cloneUser的address,user的address也会被更改。
那么怎么解决这个问题呢?其实很简单,只要将因为类型也重新clone赋值就可以,如下面的代码所示。
@Data
public class User implements Cloneable{
private Long id;
private String username;
private String password;
private Integer age;
private Character gender;
private String hobby;
private Address address;
@Override
protected Object clone() throws CloneNotSupportedException {
User cloneUser = (User)super.clone();
Address cloneAddress = (Address)this.address.clone();
cloneUser.setAddress(cloneAddress);
return cloneUser;
}
}
注意,ArrayList等集合框架也是浅Copy,使用时一定要注意这个问题