首页 > 编程知识 正文

实现一个原型模式,原型模式实例

时间:2023-05-04 22:56:51 阅读:203669 作者:1274

文章首发个人博客:https://www.xdx97.com/article/703593125049794560

一、引出原型模式

如果我们有一个类(sheep),它里面有两个属性,名称(name),年龄(age)。现在我们有一个它的实例(s1),我们需要按照这个实例的属性再去创建两个对象。


1、Sheep

@Datapublic class Sheep { private String name; private Integer age; Sheep(String name,Integer age){ this.name = name; this.age = age; }}

2、main

public class Main { public static void main(String[] args) { Sheep s1 = new Sheep("多利",1); Sheep s2 = new Sheep(s1.getName(),s1.getAge()); Sheep s3 = new Sheep(s1.getName(),s1.getAge()); }} 总结: 这样写看起来还好不麻烦也没有问题但是如果这类里面有100个属性呢?(我们写的代码会很多)或者我们现在对这个类再添加几个属性呢?(我们需要修改的地方很多)



二、原型模式

原型模式 : 用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。

也就是我们使用clone方法进行对象的创建,我们对上面的 sheep 类新增clone方法。

1、改造后的sheep类

import lombok.Data;import lombok.ToString;@Data@ToStringpublic class Sheep implements Cloneable{ private String name; private Integer age; Sheep(String name,Integer age){ this.name = name; this.age = age; } @Override protected Sheep clone() { Object obj = null; try { obj = super.clone(); }catch (Exception e){ e.printStackTrace(); } return (Sheep)obj; }}

2、main 测试

public class Main { public static void main(String[] args) { Sheep s1 = new Sheep("多利",1); Sheep s2 = s1.clone(); Sheep s3 = s1.clone(); System.out.println(s1 == s2); // false System.out.println(s2 == s3); // false }} 总结 使用clone方法去创建对象,就解决上面的问题了。但其我们的clone方法是一个浅拷贝,如果类里面有引入属性,那么创建出来的对象的引用都是指向一个的。
我们对 浅拷贝 进行一个测试

1、在上面的 sheep 类里面新增一个 属性

private Sheep friend;

2、测试

public class Main { public static void main(String[] args) { Sheep s1 = new Sheep("多利",1); s1.setFriend(new Sheep("小道仙",2)); Sheep s2 = s1.clone(); Sheep s3 = s1.clone(); System.out.println(s1.getFriend().getName() + " " + s2.getFriend().getName() + " " + s3.getFriend().getName()); s2.getFriend().setName("qkddc"); System.out.println(s1.getFriend().getName() + " " + s2.getFriend().getName() + " " + s3.getFriend().getName()); } // 打印结果如下 小道仙 小道仙 小道仙 qkddc qkddc qkddc}



三、浅拷贝、深拷贝

浅拷贝 :在拷贝对象的时候对引用类型,没有从新创建一个对象,而是指向之前对象的引用。

深拷贝 :解决浅拷贝存在的问题,我们去为引用类型创建一个新的对象。


我们使用深拷贝去解决浅拷贝的问题 方式一:使用多次clone @Overrideprotected Sheep clone() { Sheep obj = null; try { obj = (Sheep)super.clone(); if (this.getFriend() != null){ Sheep clone = this.getFriend().clone(); obj.setFriend(clone); } }catch (Exception e){ e.printStackTrace(); } return obj; } 从上面的代码我们可以看到所谓多次克隆,也就是对引用类型再进行一次克隆。优点:它写起来和理解都很简单。缺点:如果引用类型过多那么写起来很麻烦,后续如果 新增/删除 引用类型,我们还需要修改 clone 方法。
方式二:使用序列化和反序列化 (注:需要实现序列化接口 implements Serializable) @Override protected Sheep clone() { Sheep obj = null; // 创建流对象 ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { // 序列化 bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this); // 反序列化 bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis); obj = (Sheep)ois.readObject(); return obj; }catch (Exception e){ e.printStackTrace(); return null; }finally { // 关闭流 try { bos.close(); oos.close(); bis.close(); ois.close(); }catch (Exception e){ e.printStackTrace(); } } } 使用序列化优势很明显,后续 新增/删除 引用类型,我们不需要修改 clone 方法,只不过写起来稍微复杂一点。但是推荐使用这个。
两种方法的测试代码如下,结果也都一样 public class Main { public static void main(String[] args) { Sheep s1 = new Sheep("多利",1); s1.setFriend(new Sheep("小道仙",2)); Sheep s2 = s1.clone(); Sheep s3 = s1.clone(); System.out.println(s1.getFriend().getName() + " " + s2.getFriend().getName() + " " + s3.getFriend().getName()); s2.getFriend().setName("qkddc"); System.out.println(s1.getFriend().getName() + " " + s2.getFriend().getName() + " " + s3.getFriend().getName()); // 打印结果 小道仙 小道仙 小道仙 小道仙 qkddc 小道仙 }}




版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。