首页 > 其他分享 >原型模式(创建型)

原型模式(创建型)

时间:2022-09-26 11:46:02浏览次数:87  
标签:EmailPrototype2 创建 clone 模式 stu 原型 Student public

原型模式

介绍

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

简单理解,就是当需要创建一个指定的对象时,我们刚好有一个这样的对象,但是又不能直接使用,我会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

标签:EmailPrototype2,创建,clone,模式,stu,原型,Student,public
From: https://www.cnblogs.com/afei688/p/16730332.html

相关文章

  • C#创建Windows服务
    一、创建WindowsService1、新建一个WindowsService,并将项目名称改为"MyWindowsService":   2、在解决方案中将Service1.cs改为MyService.cs   3、点击查......
  • 抽象工厂模式 Abstract Factory
    “对象创建”模式通过“对象创建”模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。典型模式......
  • 二叉树的遍历方式(创建,遍历,执行)
    //binarytree.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。//#include<iostream>usingnamespacestd;typedefstructNODE{charch;N......
  • iOS13 禁用深色模式
    iOS13之后,新增了一个深色模式,但有时候我们并喜欢这个模式所以需要禁用深色模式全局禁用在info.plist文件中,添加一对key-string<key>UIUserInterfaceStyle</key><......
  • 初识设计模式 - 代理模式
    简介概念举个简单的例说明代理模式就是:假如现在需要买一辆二手车,可以自己去找车源、做质量检测等一系列车辆过户的流程,但是这实在太浪费时间和精力了,其实可以通过找中介......
  • reactor的三种模式
    Reactor响应式编程,是NIO的编程设计模式 单reactor单线程模式:简单NIO例子中,选择器循环和业务处理线程都用一个线程。也是最简单的NIO编程模式。   单Reacto......
  • 创建数据库表
    在询问窗口中编写创建数据库的代码:注意事项:使用英文,表的名称和字段,尽量使用飘号 ‘’(此页面看不出来)括起来字符串使用单引号括起来所有的语句后面加,(英文的)最......
  • 创建并部署自己的第一个区块链智能合约
    注册metaMask钱包1.下载并安装浏览器插件最好是找个梯子......
  • 设计模式---享元模式
    简述类型:结构型目的:降低对象创建时大量属性也随之被新建而带来的性能上的消耗话不多说,我们看一个案例。优化案例最初版v0现在需要采购一批办公用的电脑,以下是Compu......
  • 密码学奇妙之旅、01 CFB密文反馈模式、AES标准、Golang代码
    CFB密文反馈模式CFB密文反馈模式属于分组密码模式中的一种。加密与解密使用同一结构,加密步骤生成用于异或的密钥流。其弥补了ECB电子密码本模式的不足(明文中的重复排列会......