原型模式(创建型)

原型模式

介绍

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

简单理解,就是当需要创建一个指定的对象时,我们刚好有一个这样的对象,但是又不能直接使用,我会clone一个一模一样的新对象来使用,这就是原型模式。关键字: Clone

原型模式分为”深拷贝”和”浅拷贝”。

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

原型模式包含以下角色:

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

Java中的 Object 类中提供了 clone() 方法来实现浅拷贝。 Cloneable 接口是抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。

public class Prototype implements Cloneable {   // 具体原型类
    public Prototype() {
        System.out.println("具体的原型对象创建完成");
    }

    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Prototype) super.clone();
    }
}

public class PrototypeTest {    // 测试类
    public static void main(String[] args) throws CloneNotSupportedException {
        Prototype p1 = new Prototype();
        Prototype p2 = p1.clone();

        System.out.println("对象p1和p2是同一个对象?" + (p1 == p2));  // false
    }
}

再举个例子

现在正是秋招,投递简历会受到笔试的邮件,同一家公司发送的邮件内容除了名字不同,其他都相同,可以使用原型模式复制多个候选人邮件出来。

public class EmailPrototype implements Cloneable {
    private String name;

    public String getName() {
        return name;
    }

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

    public void show() {
        System.out.println(name + "同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!");
    }

    @Override
    protected EmailPrototype clone() throws CloneNotSupportedException {
        return (EmailPrototype) super.clone();
    }

    // 测试类
    static class EmailPrototypeTest {
        public static void main(String[] args) throws CloneNotSupportedException {
            EmailPrototype ep1 = new EmailPrototype();
            ep1.setName("张三");
            // 复制邮件
            EmailPrototype ep2 = ep1.clone();
            ep2.setName("李四");

            ep1.show();
            ep2.show();
        }
    }
}

// 运行结果:
张三同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!
李四同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!

注意点:如果具体原型类没有实现 Cloneable 接口,运行时会报异常。

使用场景:

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

(深浅拷贝)

将上面例子中属性 name 改成 Student 类型的属性,代码如下:

public class EmailPrototype2 implements Cloneable {
    // 学生类
    static class Student {
        private String name;
        private String university;

        // 省略 get set 方法

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

    private Student stu;

    public EmailPrototype2(Student stu) {
        this.stu = stu;
    }

    public Student getStu() {
        return stu;
    }

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

    public void show() {
        System.out.printf("来自%s的%s同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!%n", stu.getUniversity(), stu.getName());
    }

    @Override
    protected EmailPrototype2 clone() throws CloneNotSupportedException {
        return (EmailPrototype2) super.clone();
    }
    // 测试方法
    static class EmailPrototype2Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Student stu1 = new Student("张三", "北京大学");
            EmailPrototype2 e1 = new EmailPrototype2(stu1);

            EmailPrototype2 e2 = e1.clone();
            Student stu2 = e2.getStu();
            stu2.setName("李四");
            System.out.println("stu1和stu2是同一个对象?" + (stu2 == stu1));

            e1.show();
            e2.show();
        }
    }
}

// 运行结果
stu1和stu2是同一个对象?true
来自北京大学的李四同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!
来自北京大学的李四同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!

原型模式(创建型)

分析:e2引用对象是由e1拷贝来的,然后修改stu2中的name属性为李四,发现stu1也改了,说明stu1和stu2指向的是同一块堆内存(同一对象),这就是浅拷贝的效果。

但是这种场景下需要使用深拷贝,当前类和属性类都要实现 Cloneable 接口,代码如下:

public class EmailPrototype2 implements Cloneable {
    // 学生类
    static class Student implements Cloneable {
        private String name;
        private String university;

        // 省略 get set 方法

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

        @Override
        protected Student clone() throws CloneNotSupportedException {
            return (Student) super.clone();
        }
    }

    private Student stu;

    public EmailPrototype2(Student stu) {
        this.stu = stu;
    }

    public Student getStu() {
        return stu;
    }

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

    void show() {
        System.out.printf("来自%s的%s同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!%n", stu.getUniversity(), stu.getName());
    }

    @Override
    protected EmailPrototype2 clone() throws CloneNotSupportedException {
        EmailPrototype2 ep = (EmailPrototype2) super.clone();
        ep.setStu(ep.getStu().clone());     // 实现深拷贝这句很关键
        return ep;
    }

    static class EmailPrototype2Test {
        public static void main(String[] args) throws CloneNotSupportedException {
            Student stu1 = new Student("张三", "北京大学");
            EmailPrototype2 e1 = new EmailPrototype2(stu1);

            EmailPrototype2 e2 = e1.clone();
            Student stu2 = e2.getStu();
            stu2.setName("李四");
            System.out.println("stu1和stu2是同一个对象?" + (stu2 == stu1));

            e1.show();
            e2.show();
        }
    }
}
// 运行结果:
stu1和stu2是同一个对象?false
来自北京大学的张三同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!
来自北京大学的李四同学:您好!非常高兴邀请您参加本公司2023校园招聘在线考试,希望您能按时完成!

原型模式(创建型)

改动的地方有以下几点:

  1. 属性类Student 也要实现 Cloneable 接口,并重写 clone() 方法;
  2. 邮件类 EmailPrototype2 中重写的 clone() 方法中,要对 Student 类型的属性进行克隆;

总结

原型模式的本质就是clone,可以解决构建复杂对象的资源消耗问题,能在某些场景中提升构建对象的效率

参考

(140条消息) 23 种设计模式详解(全23种)_鬼灭之刃的博客-CSDN博客_设计模式

https://www.bilibili.com/video/BV1Np4y1z7BU

Original: https://www.cnblogs.com/afei688/p/16730332.html
Author: 阿飞的客栈
Title: 原型模式(创建型)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/644535/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • HIT软构博客6-设计模式

    设计模式可以分为1.创建型模式 2.结构型模式 3.行为类模式 1.创建型模式 ​ 工厂方法模式 ​ 当client不知道要创建哪个类的具体实例或不想在客户端代码指明要创建具体哪个…

    技术杂谈 2023年7月11日
    095
  • 阿里云视频点播

    参考示例:https://help.aliyun.com/document_detail/53406.html 注意点:有一个依赖包是下载不来的,我们需要手动下载并解压(其他包也是…

    技术杂谈 2023年6月21日
    0125
  • 关于golang:Go-mod-replace-使用

    日常开发离不开第三方库,大部分的时候,这些库都是满足咱们的须要,但有的时候,咱们须要 fork 一份,做一些批改。go mod 作为以后 go 语言的官网包管理器,天然也思考到了这…

    技术杂谈 2023年5月31日
    0115
  • 阿里云高防回源IP的限制

    高防回源IP 只能回到非阿里云的IP 高防所在阿里云账号下的SLB或者ECS IP *以及非阿里云账号下的SLB IP 一共三种情况。 posted on2022-05-17 15…

    技术杂谈 2023年5月31日
    0117
  • Git 11 不同项目设置不同提交人

    前面介绍了可以给 Git 设置全局提交人,这样当前电脑所有项目提交人都会变成设置的值。 但实际开发中有时候需要给 不同项目设置不同提交人。 比如工作的项目是一个提交人,自己维护的开…

    技术杂谈 2023年7月24日
    088
  • 强软弱虚引用,只有体会过了,才能记住

    以前学习强软弱虚引用的时候,只是走马观花看看博客,并没有自己写代码去实践、去证明,导致每次看完后,过不了多久就忘了,后来下定决心,一定要自己敲敲代码,这样才能让印象更加深刻,古人云…

    技术杂谈 2023年7月25日
    092
  • 人生苦短,我用python之三

    HTTP协议及Requests库的方法 requests库的主要方法:requests.request()构造一个请求 requests.get()获取HTML网页的主要方法,对应…

    技术杂谈 2023年7月25日
    093
  • 文件夹(?)[+]

    本文以某公司iPhone 6手机预约接口开发为例,介绍PHP5下SOAP调用的实现过程。 一、基础概念 SOAP(Simple Object Access Protocol )简单…

    技术杂谈 2023年5月31日
    096
  • TestLink在线Excel用例转换xml

    项目功能 TestLink在线Excel用例转换xml将符合用例模板的Excel测试用例,转换成xml,用于导入TestLink进行用例管理。 使用方法 1、编写测试用例 2、打开…

    技术杂谈 2023年7月11日
    074
  • Java-Stream入门

    学习Stream的目的 函数式编程渐渐变成主流,而Stream是函数式编程的重点。 相对于传统的编程方式,代码更为简洁清晰易懂。 使得并发编程变得如此简单。 有效的避免了代码嵌套地…

    技术杂谈 2023年7月11日
    071
  • 浅谈IT系统性能优化

    一个刚上线的IT系统,往往负载压力不大,所以不会存在什么性能问题。这时,人们大多只关心系统的功能性和用户体验。但是,随着时间推移,用户量和数据量都比刚上线的时候要多很多,高并发和大…

    技术杂谈 2023年7月11日
    082
  • Java — 枚举

    枚举是 JDK5 中引入的特性,由 enum 关键字来定义一个枚举类。 格式: enum 枚举类名 { 枚举项1, 枚举项2, …; 成员变量; 构造方法 成员方法 } 说明:…

    技术杂谈 2023年7月11日
    0101
  • go和delphi基于proto数据标准

    go和delphi基于proto数据标准 用代码工厂生成units.proto 用代码工厂生成DELPHI rest CRUD 用protoc将units.proto生成GO代码u…

    技术杂谈 2023年5月30日
    097
  • zabbix items 历史数据导出python脚本

    个人博客地址 http://www.darkghost.life zabbix items采集到的数据不支持页面导出,这对于需要源数据进行二次加工或生成报表来说不是很友好 做个小脚…

    技术杂谈 2023年7月25日
    094
  • WaterfallTree(瀑布树) 详细技术分析系列

    前言 WaterfallTree(瀑布树) 是最强纯C#开源NoSQL和虚拟文件系统-STSdb专有的(版权所有/专利)算法/存储结构。 参考 关于STSdb,我之前写过几篇文章,…

    技术杂谈 2023年5月31日
    0121
  • 上传文件报413 Request Entity Too Large错误解决办法

    1、nginx服务器的解决办法 修改nginx.conf的值就可以解决了将以下代码粘贴到nginx.conf内 client_max_body_size 20M; 可以选择在htt…

    技术杂谈 2023年5月31日
    0161
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球