简介
原型模式是创建型设计模式的一种。用于创建重复对象,当通过new创建对象较为复杂时可以通过原型模式简化对象创建过程,提高效率。在java中原型模式通过实现一个接口cloneable即可实现
实现
// 实体类:实现Cloneable,从写clone方法
public class Person implements Serializable, Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 测试类
public class ProtoTypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person("zhangsan", 18);
Person person1 = (Person) person.clone();
System.out.println(person.hashCode());
System.out.println(person1.hashCode());
}
}
浅克隆和深克隆
对于类的成员变量是基本数据类型和字符串类型,浅拷贝会直接进行一个值传递。对于类的成员变量是一个引用类型,浅拷贝只是会进行引用传递,克隆后的对象,其引用类型与原数据的引用类型指向的是同一个地址,此时当其中一个改变引用类型的数据时,会影响另一个对象进行相应的改变
1.代码展示
public class Person implements Serializable, Cloneable {
private String name;
private int age;
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
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 Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Address {
private String country;
private int num;
public Address(String country, int num) {
this.country = country;
this.num = num;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Address{" +
"country='" + country + '\'' +
", num=" + num +
'}';
}
}
public class ProtoTypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person("zhangsan", 18, new Address("china", 1));
Person person1 = (Person) person.clone();
System.out.println(person.getAddress() + " " + person.getAddress().hashCode());
System.out.println(person1.getAddress() + " " + person1.getAddress().hashCode());
// 输出:Address{country='china', num=1} 356573597
// Address{country='china', num=1} 356573597
person.getAddress().setCountry("us");
System.out.println(person.getAddress() + " " + person.getAddress().hashCode());
System.out.println(person1.getAddress() + " " + person1.getAddress().hashCode());
// 输出:Address{country='us', num=1} 356573597
// Address{country='us', num=1} 356573597
}
}
可以看到,person里面有引用成员变量Address,当对person对象进行拷贝时,两个对象的address指的是同一个对象,当修改其中一个的属性值,另一个对象也跟着一起改变
深拷贝实现方式1:重写克隆方法实现
public class Person implements Serializable, Cloneable {
private String name;
private int age;
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
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 Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
Person person = (Person)super.clone();
// 引用成员变量也通过重写来实现
person.setAddress((Address)address.clone());
return person;
}
}
public class Address implements Cloneable{
private String country;
private int num;
public Address(String country, int num) {
this.country = country;
this.num = num;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Address{" +
"country='" + country + '\'' +
", num=" + num +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
该实现存在的问题:对于每个引用成员变量,其对应的类必须实现Cloneable接口,重写clone方法,如果该类中也存在引用成员变量也要进行相同处理。
深拷贝实现2:通过序列化和反序列化实现
public class Person implements Serializable{
private String name;
private int age;
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
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 Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
public Object deepClone(){
Object person = null;
try {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
person = ois.readObject();
// 释放资源
ois.close();
oos.close();
} catch (Exception e) {
e.getMessage();
}
return person;
}
}
public class Address implements Serializable {
private String country;
private int num;
public Address(String country, int num) {
this.country = country;
this.num = num;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Address{" +
"country='" + country + '\'' +
", num=" + num +
'}';
}
}
该方法必须实现Serializable接口