02.原型模式
prototype:以一个已创建的实例作为原型,复制该对象来创建一个和原型相同或类似的新对象
1. 应用场景
对象之间相同或类似,只有个别属性不同
创建对象成本较大,如初始化时间长、占CPU多】占网络资源多的
创建一个对象需要繁琐的数据准备或访问权限等
系统中大量使用该类对象,各个调用者都需要给它的属性重新赋值
基于原型模式通过深度克隆保存对象状态,可实现存档、撤销操作等功能
2. java
借助Object类的clone()方法,基于内存二进制流的复制,性能上比new更快
但需要为每个要复制的类实现clone方法,在深度克隆时,可能有多层都要实现clone方法
当类有很多层时,可通过序列化的方法克隆
3.1 基于clone的
Address类:
import lombok.Data; @Data public class Address implements Cloneable{ private String province; private String city; public Address(String province, String city) { this.province = province; this.city = city; } @Override protected Object clone() { Address address = null; try { address = (Address)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return address; } @Override public String toString() { return province + "," + city; } }
Person类:
import lombok.Data; @Data public class Person implements Cloneable{ private String name; private String number; private Address address; public Person(String name, String number, Address address) { this.name = name; this.number = number; this.address = address; } @Override protected Object clone() { Person person = null; try { //浅复制 person = (Person)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } //深复制 person.address = (Address)address.clone(); return person; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", number='" + number + '\'' + ", address=" + address + '}'; } }
测试:
Address address1 = new Address("hunan","changsha"); Person person1 = new Person("p1","202001",address1); Person person2 = (Person)person1.clone(); //person2和person1是彼此独立的两个对象 System.out.println(person1); //p1,202001,hunan,changsha System.out.println(person2); //p1,202001,hunan,changsha address1.setCity("hengyang"); System.out.println(person1); //p1,202001,hunan,hengyang System.out.println(person2); //p1,202001,hunan,hengyang
3.2 序列化
Address2类:
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import java.io.Serializable; @Getter @Setter @AllArgsConstructor public class Address2 implements Serializable { private static final long serialVersionUID = -8861093654104009060L; private String province; private String city; @Override public String toString() { return province + "," + city; } }
Person2类:
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import java.io.*; @Getter @Setter @AllArgsConstructor public class Person2 implements Serializable { private String name; private String number; private Address2 address; public Person2 myClone() { Person2 person2 = null; ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; ByteArrayInputStream bais = null; ObjectInputStream ois = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); //当前对象序列化 oos.writeObject(this); //将流--->对象 bais = new ByteArrayInputStream(baos.toByteArray()); ois = new ObjectInputStream(bais); person2 = (Person2)ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } finally { if(null != baos) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != bais) { try { bais.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != oos) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != ois) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } return person2; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", number='" + number + '\'' + ", address=" + address + '}'; } }
测试:
Address2 address = new Address2("hunan","changsha"); Person2 person = new Person2("p1","202001",address); Person2 person2 = person.myClone(); System.out.println(person); //Person{name='p1', number='202001', address=hunan,changsha} System.out.println(person2); //Person{name='p1', number='202001', address=hunan,changsha} address.setCity("hengyang"); System.out.println(person); //Person{name='p1', number='202001', address=hunan,hengyang} System.out.println(person2); //Person{name='p1', number='202001', address=hunan,changsha}
一个工具对象克隆的工具类:
package util.obj; import java.io.*; public final class ObjClone { /** * 对象深度复制 * @param srcObj * @param <T> * @return */ public static <T> T deepClone(T srcObj){ T cloneObj = null; ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; ByteArrayInputStream bais = null; ObjectInputStream ois = null; try { //对象序列化到流 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(srcObj); //流转对象 bais = new ByteArrayInputStream(baos.toByteArray()); ois = new ObjectInputStream(bais); cloneObj = (T) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } finally { closeStream(baos,oos,bais,ois); } return cloneObj; } private static void closeStream(ByteArrayOutputStream baos, ObjectOutputStream oos,ByteArrayInputStream bais,ObjectInputStream ois) { if(null != baos) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != bais) { try { bais.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != oos) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != ois) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3. C++
4.
5. 原型模式扩展
增加原型管理类,用一个结构存储各个对象,需要各个对象的第三方找这个原型管理类索取对象而不是直接去复制对象。