1. 前言

原型模式从根本上来说就是Java中的对象克隆,针对于对象的浅拷贝和深拷贝,Java中提供了两种实现方式:

  • 实现Cloneable接口并重写clone()
  • 实现Serializable 接口,通过序列化和反序列化实现深拷贝

相较于前面的单例模式和工厂模式,对象克隆的开销相对较大,它通常主要应用于以下场景:

  • 依赖于外部资源或硬件密集型操作进行新对象的创建的场景
  • 获取相同对象在相同状态的拷贝而无须进行重复获取状态操作的场景
  • 在不确定所属具体类时需要对象的实例的场景

关于Java中对象的克隆,在前面的图解Java中的浅拷贝和深拷贝已经讲述的很清楚了,不了解的可自行查阅。因此,原型模式中所涉及的对象克隆的相关内容这里就不再赘述,而是通过一个例子来回顾下相关的内容,同时加深理解下原型模式。

2. 案例

天行者崛起.jpg

西斯大帝为了消灭最后的天行者(SkyWalker)并再次卷土重来统治银河系,秘密的在Exegol秘密的建造了一支称为Final Order的军队,军队的主要战力就是歼星舰,每艘歼星舰都是名字和攻击力,以及都配备了一名将军。
歼星舰.png

首先我们需要创建将军类General:

  1. public class General implements Serializable, Cloneable{
  2. String name;
  3. public General(String name) {
  4. this.name = name;
  5. }
  6. @Override
  7. public String toString() {
  8. return "General{" +
  9. "name='" + name + '\'' +
  10. '}';
  11. }
  12. @Override
  13. protected Object clone() throws CloneNotSupportedException {
  14. return super.clone();
  15. }
  16. }

General实现了Serializable和Cloneable两个接口。然后创建歼星舰类StarDestroyer:

  1. public class StarDestroyer implements Serializable, Cloneable {
  2. private String name;
  3. private double attack;
  4. private General general;
  5. public StarDestroyer(String name, double attack, General general) {
  6. this.name = name;
  7. this.attack = attack;
  8. this.general = general;
  9. }
  10. @Override
  11. public String toString() {
  12. return "StarDestroyer{" +
  13. "name='" + name + '\'' +
  14. ", attack=" + attack +
  15. ", general=" + general +
  16. '}';
  17. }
  18. @Override
  19. protected Object clone() throws CloneNotSupportedException{
  20. StarDestroyer sd = (StarDestroyer) super.clone();
  21. sd.general = (General) general.clone();
  22. return sd;
  23. }
  24. public Object deepCopy() throws IOException {
  25. StarDestroyer starDestroyer = null;
  26. ByteArrayInputStream bis = null;
  27. ByteArrayOutputStream bos = null;
  28. ObjectInputStream ois = null;
  29. ObjectOutputStream oos = null;
  30. try{
  31. bos = new ByteArrayOutputStream();
  32. oos = new ObjectOutputStream(bos);
  33. oos.writeObject(this);
  34. bis = new ByteArrayInputStream(bos.toByteArray());
  35. ois = new ObjectInputStream(bis);
  36. starDestroyer = (StarDestroyer) ois.readObject();
  37. return starDestroyer;
  38. } catch (Exception e){
  39. e.printStackTrace();
  40. } finally {
  41. bis.close();
  42. bos.close();
  43. ois.close();
  44. oos.close();
  45. }
  46. return starDestroyer;
  47. }
  48. }

由于西斯大帝的信徒众多,因此歼星舰可以在不同的星球采用不同的技术建造。在掌握了歼星舰的建造技术和信徒后,西斯大帝开始命令信徒全力组建Final Order:

  1. public class Sith {
  2. public static void main(String[] args) throws CloneNotSupportedException, IOException {
  3. StarDestroyer starDestroyer = new StarDestroyer("starDestroyer", 10000.0, new General("Lun"));
  4. StarDestroyer two = (StarDestroyer) starDestroyer.clone();
  5. System.out.println(starDestroyer);
  6. System.out.println(two);
  7. System.out.println(starDestroyer == two);
  8. }
  9. }

首先验收了第一个信徒的工作,发现是合格的,命令他加快步伐:

  1. StarDestroyer{name='starDestroyer', attack=10000.0, general=prototype.General@2dda6444}
  2. StarDestroyer{name='starDestroyer', attack=10000.0, general=prototype.General@5e9f23b4}
  3. false

然后验收了第二个信徒的工作,发现也不错,鼓励他再接再厉

  1. public class Sith {
  2. public static void main(String[] args) throws CloneNotSupportedException, IOException {
  3. StarDestroyer starDestroyer = new StarDestroyer("one", 10000.0, new General("Lun"));
  4. StarDestroyer two = (StarDestroyer) starDestroyer.clone();
  5. StarDestroyer three = (StarDestroyer) starDestroyer.deepCopy();
  6. System.out.println(three);
  7. System.out.println(starDestroyer == three);
  8. }
  9. }
  1. StarDestroyer{name='starDestroyer', attack=10000.0, general=General{name='Lun'}}
  2. false

最后西斯大帝拥有了一支庞大的军队,但黑暗永远无法战胜光明,最后的天行者带领抵抗组织和全银河系的平民打败了西斯大帝,赢得了最后的胜利。