原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
模拟深浅copy 文件,文件附件 copy
附件
/*** @author meikb* @desc* @date 2020-05-23 09:58*/public class Attachment implements Serializable {private String name;private String path;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}@Overridepublic String toString() {return "Attachment{" +"name='" + name + '\'' +", path='" + path + '\'' +'}';}}
日志文件类
public class WeeklyLog implements Serializable , Cloneable{private static final long serialVersionUID = 1L;private Attachment attachment;private String name;public Attachment getAttachment() {return attachment;}public void setAttachment(Attachment attachment) {this.attachment = attachment;}public String getName() {return name;}public void setName(String name) {this.name = name;}public WeeklyLog deepClone() throws IOException, ClassNotFoundException{// 将对象写入流中ByteArrayOutputStream bao = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bao);oos.writeObject(this);// 将对象从流中取出ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (WeeklyLog) ois.readObject();}//使用clone()方法实现浅克隆public WeeklyLog clone(){Object obj = null;try{//克隆当前对象obj = super.clone();return (WeeklyLog)obj;}catch(CloneNotSupportedException e){System.out.println("不支持复制!");return null;}}}
测试主函数
/*** @author meikb* @desc* 1.java Object提供的克隆的方法是浅克隆* * 只能克隆基本数据类型 、 如果原型对象的成员变量是引用类型 、那么只克隆引用对象的地址 、 相同地址指向同一个引用对象* * 2. 深度克隆指的是 原型对象实现Serializable 接口 、当在clone的时候把当前对象序列化后 再 反序列化 得到相同的对象* @date 2020-05-23 09:59*/public class PrototypeMain {public static void main(String[] args) {WeeklyLog weeklyLog = new WeeklyLog();Attachment attachment = new Attachment();attachment.setName("附件");attachment.setPath("/a/b/c");weeklyLog.setName("日志1");weeklyLog.setAttachment(attachment);WeeklyLog weeklyLog1 = weeklyLog.clone();WeeklyLog weeklyLog2 = weeklyLog.deepClone();System.out.println(weeklyLog1);System.out.println(weeklyLog2);System.out.println(weeklyLog == weeklyLog1);System.out.println(weeklyLog == weeklyLog2);System.out.println(weeklyLog.getAttachment() == weeklyLog1.getAttachment());System.out.println(weeklyLog.getAttachment() == weeklyLog2.getAttachment());}}//WeeklyLog{attachment=Attachment{name='附件', path='/a/b/c'}, name='日志1'}WeeklyLog{attachment=Attachment{name='附件', path='/a/b/c'}, name='日志1'}falsefalsetruefalse
