Java设计模式之原型模式详细解析

 更新时间:2023年11月23日 10:45:59   作者:Super_Leng  
这篇文章主要介绍了Java设计模式之原型模式详细解析,原型模式就是用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象,需要的朋友可以参考下

一、原型模式

1. 概述

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

2. 结构

原型模式包含如下角色:

抽象原型类:规定了具体原型对象必须实现的 clone() 方法。具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。访问类:使用具体原型类中的 clone() 方法来复制新的对象。

接口类图如下:

在这里插入图片描述

3. 实现

原型模式的克隆分为浅克隆和深克隆。

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

Java中的Object类中提供了 clone() 方法来实现浅克隆。

Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。

Realizetype(具体的原型类):

public class Realizetype implements Cloneable {

    public Realizetype() {
        System.out.println("具体的原型对象创建完成!");
    }

    @Override
    public Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");

        return (Realizetype) super.clone();
    }
}

PrototypeTest(测试访问类):

public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一个原型类对象
        Realizetype realizetype = new Realizetype();

        //调用Realizetype类中的clone方法进行对象的克隆
        Realizetype clone = realizetype.clone();

        System.out.println("原型对象和克隆出来的是否是同一个对象?" + (realizetype == clone));
    }
}

运行结果为:

在这里插入图片描述

4. 案例

用原型模式生成“三好学生”奖状

同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的名字即可。

在这里插入图片描述

奖状类:

public class Citation implements Cloneable {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return (this.name);
    }

    public void show() {
        System.out.println(name + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

测试访问类:

public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation c1 = new Citation();
        c1.setName("张三");

        //复制奖状
        Citation c2 = c1.clone();
        //将奖状的名字修改李四
        c2.setName("李四");

        c1.show();
        c2.show();
    }
}

运行结果为:

在这里插入图片描述

5 使用场景

  • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。
  • 性能和安全要求比较高。

6 扩展(深克隆)

将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。

奖状类:

public class Citation implements Cloneable {
    private Student stu;

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

    void show() {
        System.out.println(stu.getName() + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

学生类:

public class Student {
    private String name;
    private String address;

    public Student(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public Student() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

测试类:

public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        Citation c1 = new Citation();
        Student stu = new Student("张三", "西安");
        c1.setStu(stu);

        //复制奖状
        Citation c2 = c1.clone();
        //获取c2奖状所属学生对象
        Student stu1 = c2.getStu();
        stu1.setName("李四");

        //判断stu对象和stu1对象是否是同一个对象
        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

运行结果为:

在这里插入图片描述

说明: ​ stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。

这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。

这种情况需要使用深克隆,而进行深克隆需要使用对象流。

public class CitationTest1 {
    public static void main(String[] args) throws Exception {
        Citation c1 = new Citation();
        Student stu = new Student("张三", "西安");
        c1.setStu(stu);

        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //将c1对象写出到文件中
        oos.writeObject(c1);
        oos.close();

        //创建对象出入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //读取对象
        Citation c2 = (Citation) ois.readObject();
        //获取c2奖状所属学生对象
        Student stu1 = c2.getStu();
        stu1.setName("李四");

        //判断stu对象和stu1对象是否是同一个对象
        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

运行结果为:

在这里插入图片描述

注意:Citation类和Student类必须实现Serializable接口,否则会抛NotSerializableException异常。

到此这篇关于Java设计模式之原型模式详细解析的文章就介绍到这了,更多相关Java中的原型模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot中的@Configuration注解详解

    SpringBoot中的@Configuration注解详解

    这篇文章主要介绍了SpringBoot中的@Configuration注解详解,Spring Boot推荐使用JAVA配置来完全代替XML 配置,JAVA配置就是通过 @Configuration和 @Bean两个注解实现的,需要的朋友可以参考下
    2023-08-08
  • 详细了解JAVA NIO之Buffer(缓冲区)

    详细了解JAVA NIO之Buffer(缓冲区)

    这篇文章主要介绍了JAVA NIO之Buffer(缓冲区)的相关资料,文中讲解非常细致,帮助大家更好的学习JAVA NIO,感兴趣的朋友可以了解下
    2020-07-07
  • MyBatis中的@SelectProvider注解源码分析

    MyBatis中的@SelectProvider注解源码分析

    这篇文章主要介绍了MyBatis中的@SelectProvider注解源码分析,@SelectProvider功能就是用来单独写一个class类与方法,用来提供一些xml或者注解中不好写的sql,今天就来说下这个注解的具体用法与源码,需要的朋友可以参考下
    2024-01-01
  • springboot加载命令行参数ApplicationArguments的实现

    springboot加载命令行参数ApplicationArguments的实现

    本文主要介绍了springboot加载命令行参数ApplicationArguments的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • struts中动态方法调用使用通配符

    struts中动态方法调用使用通配符

    这篇文章主要介绍了struts中动态方法调用使用通配符的相关资料,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧
    2016-09-09
  • SpringMVC实现文件上传下载的全过程

    SpringMVC实现文件上传下载的全过程

    对于上传功能,我们在项目中是经常会用到的,比如用户注册的时候,上传用户头像,这个时候就会使用到上传的功能,而对于下载使用场景也很常见,下面这篇文章主要给大家介绍了关于SpringMVC实现文件上传下载的相关资料,需要的朋友可以参考下
    2022-01-01
  • JavaCV摄像头实战之实现口罩检测

    JavaCV摄像头实战之实现口罩检测

    这篇文章主要介绍了利用JavaCV实现口罩检测,功能是检测摄像头内的人是否带了口罩,把检测结果实时标注在预览窗口。感兴趣的可以试一试
    2022-01-01
  • Hibernate连接三种数据库的配置文件

    Hibernate连接三种数据库的配置文件

    今天小编就为大家分享一篇关于Hibernate连接三种数据库的配置文件,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Swing常用组件之多行文本区JTextArea

    Swing常用组件之多行文本区JTextArea

    这篇文章主要为大家详细介绍了Swing常用组件之多行文本区JTextArea,感兴趣的朋友可以参考一下
    2016-05-05
  • springCloud集成nacos启动时报错原因排查

    springCloud集成nacos启动时报错原因排查

    这篇文章主要介绍了springCloud集成nacos启动时报错原因排查,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论