• Java学习 --- 设计模式的原型模式


    目录

    一、问题需求

    二、原型模式(Prototype)

    三、原型模式在spring源码的使用

     四、浅拷贝与深拷贝

    4.1、浅拷贝

    4.2、深拷贝

    方式一:使用clone方法完成

    方式二、通过对象序列化实现深拷贝(推荐)

    五、原型模式注意事项


    一、问题需求

    有一只羊叫tom,姓名:tom,年龄:1,颜色:白色,创建十只和tom属性一样的羊。

    使用普通方法创建的示例代码:

    1. public class Sheep {
    2. private String name;
    3. private int age;
    4. private String color;
    5. public Sheep(String name, int age, String color) {
    6. this.name = name;
    7. this.age = age;
    8. this.color = color;
    9. }
    10. public String getName() {
    11. return name;
    12. }
    13. public void setName(String name) {
    14. this.name = name;
    15. }
    16. public int getAge() {
    17. return age;
    18. }
    19. public void setAge(int age) {
    20. this.age = age;
    21. }
    22. public String getColor() {
    23. return color;
    24. }
    25. public void setColor(String color) {
    26. this.color = color;
    27. }
    28. @Override
    29. public String toString() {
    30. return "Sheep{" +
    31. "name='" + name + '\'' +
    32. ", age=" + age +
    33. ", color='" + color + '\'' +
    34. '}';
    35. }
    36. }
    1. public class Client {
    2. public static void main(String[] args) {
    3. Sheep sheep = new Sheep("tom", 1, "白色");
    4. Sheep sheep1 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    5. Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    6. Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
    7. //创建十只羊省略
    8. System.out.println("sheep1 = " + sheep1);
    9. System.out.println("sheep2 = " + sheep2);
    10. System.out.println("sheep3 = " + sheep3);
    11. }
    12. }

    代码分析:

    1、简单,好理解,易操作。

    2、在创建新的对象时,总是要获取原始对象的属性,在创建对象复杂时,效率低下。

    3、总是需要重新初始化对象,不是动态地获得对象运行时的状态,不灵活。

    解决方法:Java中Object类是所有类的根类,Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但需要实现clone的Java类必须要实现一个接口Cloneable,该接口表示这个类能够复制且具备有复制的能力 =》原型模式。

    二、原型模式(Prototype)

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

    2、原型模式是一种创建型设计模式,允许一个对象再创建另一个可定制的对象,无需知道如何创建的细节。

    3、原理:通过将一个原型对象传给要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝到它们自己来实施创建。

    使用原型模式改进的示例代码:

    1. public class Sheep implements Cloneable {
    2. private String name;
    3. private int age;
    4. private String color;
    5. public Sheep(String name, int age, String color) {
    6. this.name = name;
    7. this.age = age;
    8. this.color = color;
    9. }
    10. public String getName() {
    11. return name;
    12. }
    13. public void setName(String name) {
    14. this.name = name;
    15. }
    16. public int getAge() {
    17. return age;
    18. }
    19. public void setAge(int age) {
    20. this.age = age;
    21. }
    22. public String getColor() {
    23. return color;
    24. }
    25. public void setColor(String color) {
    26. this.color = color;
    27. }
    28. @Override
    29. public String toString() {
    30. return "Sheep{" +
    31. "name='" + name + '\'' +
    32. ", age=" + age +
    33. ", color='" + color + '\'' +
    34. '}';
    35. }
    36. //克隆该实例,默认的clone()完成
    37. @Override
    38. protected Object clone() {
    39. Sheep sheep = null;
    40. try {
    41. sheep = (Sheep) super.clone();
    42. } catch (Exception e) {
    43. System.out.println(e.getMessage());
    44. }
    45. return sheep;
    46. }
    47. }
    1. public class Client {
    2. public static void main(String[] args) {
    3. Sheep sheep = new Sheep("tom", 1, "白色");
    4. Sheep sheep1 = (Sheep) sheep.clone();
    5. Sheep sheep2 = (Sheep) sheep.clone();
    6. Sheep sheep3 = (Sheep) sheep.clone();
    7. Sheep sheep4 = (Sheep) sheep.clone();
    8. //省略后面的羊。。。。
    9. System.out.println("sheep1 = " + sheep1);
    10. System.out.println("sheep2 = " + sheep2);
    11. System.out.println("sheep3 = " + sheep3);
    12. System.out.println("sheep4 = " + sheep4);
    13. }
    14. }

    三、原型模式在spring源码的使用

    在spring中原型bean的创建,就是原型模式

    项目结构:

    测试参考代码:

    1. public class Sheep {
    2. private String name = "tom";
    3. private int age = 1;
    4. private String color = "白色";
    5. public Sheep() {
    6. }
    7. public Sheep(String name, int age, String color) {
    8. this.name = name;
    9. this.age = age;
    10. this.color = color;
    11. }
    12. public String getName() {
    13. return name;
    14. }
    15. public void setName(String name) {
    16. this.name = name;
    17. }
    18. public int getAge() {
    19. return age;
    20. }
    21. public void setAge(int age) {
    22. this.age = age;
    23. }
    24. public String getColor() {
    25. return color;
    26. }
    27. public void setColor(String color) {
    28. this.color = color;
    29. }
    30. @Override
    31. public String toString() {
    32. return "Sheep{" +
    33. "name='" + name + '\'' +
    34. ", age=" + age +
    35. ", color='" + color + '\'' +
    36. '}';
    37. }
    38. }

    在maven中pom.xml配置

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframeworkgroupId>
    4. <artifactId>spring-contextartifactId>
    5. <version>5.2.5.RELEASEversion>
    6. dependency>
    7. dependencies>

    配置beans.xml文件

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="sheep" class="com.cjc.bean.Sheep" scope="prototype">bean>
    5. beans>

    测试用例:

    1. public class ProtoType {
    2. public static void main(String[] args) {
    3. ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    4. //通过id获取sheep
    5. Object sheep1 = applicationContext.getBean("sheep");
    6. System.out.println("sheep1 = " + sheep1);
    7. Object sheep2 = applicationContext.getBean("sheep");
    8. System.out.println("sheep2 = " + sheep2);
    9. System.out.println(sheep1 == sheep2); //如果是原型模式创建,则两个实例对象判断为false
    10. }
    11. }

    源码分析:

    第一步:

     第二步:

     第三步:

     四、浅拷贝与深拷贝

    4.1、浅拷贝

    1、对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,就是将该属性值复制一份给新的对象。

    2、当数据类型是引用数据类型的成员变量,如数组,类的对象等,浅拷贝会进行引用传递,只是将该成员变量的引用值(内存地址)复制一份给新的对象。实际上两个对象的该成员变量都指向同一个实例。此时修改一个对象中成员变量会影响到另一个对象的该成员变量的值

    3、浅拷贝就是使用默认的clone()方法来实现。

    示例参考代码:

    1. public class Sheep implements Cloneable {
    2. //使用对象做属性
    3. private Sheep sheep;
    4. public Sheep getSheep() {
    5. return sheep;
    6. }
    7. public void setSheep(Sheep sheep) {
    8. this.sheep = sheep;
    9. }
    10. //克隆该实例,默认的clone()完成
    11. @Override
    12. protected Object clone() {
    13. Sheep sheep = null;
    14. try {
    15. sheep = (Sheep) super.clone();
    16. } catch (Exception e) {
    17. System.out.println(e.getMessage());
    18. }
    19. return sheep;
    20. }
    21. }
    1. public class Client {
    2. public static void main(String[] args) {
    3. Sheep sheep = new Sheep();
    4. sheep.setSheep(new Sheep());
    5. Sheep sheep1 = (Sheep) sheep.clone();
    6. Sheep sheep2 = (Sheep) sheep.clone();
    7. Sheep sheep3 = (Sheep) sheep.clone();
    8. System.out.println("sheep1 = " + sheep1 + "sheep1.sheep= " + sheep1.getSheep().hashCode());
    9. System.out.println("sheep2 = " + sheep2 + "sheep2.sheep= " + sheep2.getSheep().hashCode());
    10. }
    11. }

    4.2、深拷贝

    1、复制对象的所有基本数据类型的成员变量的值

    2、为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型的成员变量所引用的对象,直到该对象可达的所有对象。对象进行深拷贝要对整个对象进行拷贝。

    方式一:使用clone方法完成

    示例参考代码:

    1. public class DeepCloneable implements Cloneable {
    2. private String cloneName;
    3. private String cloneClass;
    4. //构造器
    5. public DeepCloneable(String cloneName, String cloneClass) {
    6. this.cloneName = cloneName;
    7. this.cloneClass = cloneClass;
    8. }
    9. //属性都是String类型,使用默认的clone方法即可
    10. @Override
    11. protected Object clone() throws CloneNotSupportedException {
    12. return super.clone();
    13. }
    14. }
    1. public class DeepProtoType implements Cloneable {
    2. private String name;
    3. private DeepCloneable deepCloneable;
    4. public String getName() {
    5. return name;
    6. }
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. public DeepCloneable getDeepCloneable() {
    11. return deepCloneable;
    12. }
    13. public void setDeepCloneable(DeepCloneable deepCloneable) {
    14. this.deepCloneable = deepCloneable;
    15. }
    16. public DeepProtoType() {
    17. }
    18. @Override
    19. protected Object clone() throws CloneNotSupportedException {
    20. Object deep = null;
    21. //对基本数据类型和String的克隆
    22. deep = super.clone();
    23. DeepProtoType deepProtoType = (DeepProtoType)deep;
    24. //完成对引用类型的处理
    25. deepProtoType.deepCloneable = (DeepCloneable) deepCloneable.clone();
    26. return deepProtoType;
    27. }
    28. }
    1. public class Client {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. DeepProtoType deepProtoType = new DeepProtoType();
    4. deepProtoType.setName("成都");
    5. deepProtoType.setDeepCloneable(new DeepCloneable("金牛","西南交大"));
    6. DeepProtoType deepProtoType1 = (DeepProtoType) deepProtoType.clone();
    7. System.out.println("deepProtoType.getName() = " + deepProtoType.getName());
    8. System.out.println("deepProtoType1.getName() = " + deepProtoType1.getName());
    9. System.out.println("deepProtoType.getDeepCloneable() = " + deepProtoType.getDeepCloneable().hashCode());
    10. System.out.println("deepProtoType1.getDeepCloneable() = " + deepProtoType1.getDeepCloneable().hashCode());
    11. }
    12. }

    方式二、通过对象序列化实现深拷贝(推荐)

    示例参考代码:

    1. public class DeepCloneable implements Serializable {
    2. private static final long serialVersionUID = 1L;
    3. private String cloneName;
    4. private String cloneClass;
    5. //构造器
    6. public DeepCloneable(String cloneName, String cloneClass) {
    7. this.cloneName = cloneName;
    8. this.cloneClass = cloneClass;
    9. }
    10. //属性都是String类型,使用默认的clone方法即可
    11. @Override
    12. protected Object clone() throws CloneNotSupportedException {
    13. return super.clone();
    14. }
    15. }
    1. public class DeepProtoType implements Serializable {
    2. private String name;
    3. private DeepCloneable deepCloneable;
    4. public String getName() {
    5. return name;
    6. }
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. public DeepCloneable getDeepCloneable() {
    11. return deepCloneable;
    12. }
    13. public void setDeepCloneable(DeepCloneable deepCloneable) {
    14. this.deepCloneable = deepCloneable;
    15. }
    16. public DeepProtoType() {
    17. }
    18. public Object deepClone(){
    19. //创建流对象
    20. ByteArrayOutputStream byteArrayOutputStream = null;
    21. ObjectOutputStream outputStream = null ;
    22. ByteArrayInputStream byteArrayInputStream = null;
    23. ObjectInputStream objectInputStream = null;
    24. try {
    25. //序列化
    26. byteArrayOutputStream = new ByteArrayOutputStream();
    27. outputStream = new ObjectOutputStream(byteArrayOutputStream);
    28. outputStream.writeObject(this);//当前对象以对象流的方式输出
    29. //反序列化
    30. byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    31. objectInputStream = new ObjectInputStream(byteArrayInputStream);
    32. DeepProtoType deepProtoType = (DeepProtoType) objectInputStream.readObject();
    33. return deepProtoType;
    34. } catch (Exception e) {
    35. e.printStackTrace();
    36. return null;
    37. } finally {
    38. //关闭流
    39. try {
    40. byteArrayOutputStream.close();
    41. outputStream.close();
    42. byteArrayInputStream.close();
    43. objectInputStream.close();
    44. } catch (IOException e) {
    45. e.printStackTrace();
    46. }
    47. }
    48. }
    49. }
    1. public class Client {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. DeepProtoType deepProtoType = new DeepProtoType();
    4. deepProtoType.setName("成都");
    5. deepProtoType.setDeepCloneable(new DeepCloneable("金牛","西南交大"));
    6. DeepProtoType deepProtoType1 = (DeepProtoType) deepProtoType.deepClone();
    7. System.out.println("deepProtoType.getName() = " + deepProtoType.getName());
    8. System.out.println("deepProtoType1.getName() = " + deepProtoType1.getName());
    9. System.out.println("deepProtoType.getDeepCloneable() = " + deepProtoType.getDeepCloneable().hashCode());
    10. System.out.println("deepProtoType1.getDeepCloneable() = " + deepProtoType1.getDeepCloneable().hashCode());
    11. }
    12. }

    五、原型模式注意事项

    1、创建新的对象比较复杂时,可以利用原型模式简化对像的创建过程,同时也能够提高效率。

    2、不用重新初始化对象,而是动态地获得对象运行时的状态。

    3、原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,不需要修改代码。

    4、原型模式在实现深拷贝的时候需要复杂的代码。

    5、原型模式需要给每个类配备一个克隆方法,这对全新的类不是什么问题,但对已有的类进行改造就要修改其源码,违背ocp原则。

  • 相关阅读:
    【MySQL】什么是索引?如何选择索引类型?
    计算机毕业设计Java的商城后台管理系统(源码+系统+mysql数据库+lw文档)
    Java学习笔记(四)
    妇女节颜值h5投票活动开展的作用是什么
    Hadoop修改pid文件存储+配置YARN+运行默认YARN例子
    1095 Cars on Campus
    擎创技术流 | 深入浅出运维可观测工具(三):eBPF如何兼容多架构模式性能管理
    CSP常用算法
    viewport 视口
    [从零开始学习FPGA编程-56]:视野篇-常见概念:chip(芯片)、chipset(芯片组)、chiplet(芯粒)、die(裸片)的区别
  • 原文地址:https://blog.csdn.net/qq_46093575/article/details/126130563