原型模式

1. 使用场景

  • 当一个对象的创建过程非常复杂,而我们需要不断复制一个已存在对象的状态时。
  • 为了防止可变对象被其它方法误修改,有必要进行保护性拷贝时

2. 实现举例

希望根据一个已有的Student对象,复制(克隆)另一个新的Student对象:

深拷贝

class Student implements Serializable { private static final long serialVersionUID = 1L; int id; String name; Date birthday; public Student(int id, String name, Date birthday) { super(); this.id = id; this.name = name; this.birthday = birthday; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", birthday=" + birthday + "]"; } public Student clone() { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(this); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); ObjectInputStream ois = new ObjectInputStream(is); return (Student) ois.readObject(); } catch (ClassNotFoundException | IOException e) { throw new RuntimeException(e); } } }

使用:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Student s1 = new Student(1, "张三", sdf.parse("1995-05-21")); Student s2 = s1.clone(); System.out.println(s1); System.out.println(s2); System.out.println(s2 == s1); System.out.println(s2.birthday == s1.birthday);

输出:

Student [id=1, name=张三, birthday=Sun May 21 00:00:00 CST 1995]
Student [id=1, name=张三, birthday=Sun May 21 00:00:00 CST 1995]
false
false

要点

  • 利用了对象流和数组流进行了byte级别的复制,效率较高
  • 因为是byte级别的复制,因此各个field都成功复制产生了新的对象
  • 需要实现Serializable接口,类中的各个field 也需要实现Serializable

浅拷贝

class Student implements Cloneable { int id; String name; Date birthday; public Student(int id, String name, Date birthday) { super(); this.id = id; this.name = name; this.birthday = birthday; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", birthday=" + birthday + "]"; } public Student clone() { try { return (Student) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } }

使用:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Student s1 = new Student(1, "张三", sdf.parse("1995-05-21")); Student s2 = s1.clone(); System.out.println(s1); System.out.println(s2); System.out.println(s2 == s1); System.out.println(s2.birthday == s1.birthday);

输出:

Student [id=1, name=张三, birthday=Sun May 21 00:00:00 CST 1995]
Student [id=1, name=张三, birthday=Sun May 21 00:00:00 CST 1995]
false
true

要点

  • 利用了native clone方法进行了复制,要求类实现Cloneable接口
  • native clone 的特点是
    • 对于String,因为String属于不可变对象,clone时虽然也是复制了String的引用,但实际使用时不会影响
    • 对于Date则有问题,因为Date是可变对象,clone时仅仅复制了它的引用,克隆后的对象如果Date的内容发生了修改,会影响原来的

results matching ""

    No results matching ""