10 创建型模式-原型模式

news2024/11/17 21:25:23

引言:
创建对象的五种方式:

  1. 通过new关键字
  2. 通过Class类的newInstance()方法
  3. 通过Constructor类的newInstance()方法
  4. 利用Clone方法
  5. 反序列化

Clone方法:
其实现方式正是通过调用 Object 类的 clone() 方法来完成。

protected native Object clone() throws CloneNotSupportedException;
public class Person implements Cloneable{
    public String pname;
    public int page;
    public Address address;
    public Person() {}
    
    public Person(String pname,int page){
        this.pname = pname;
        this.page = page;
        this.address = new Address();
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    public void setAddress(String provices,String city ){
        address.setAddress(provices, city);
    }
    public void display(String name){
        System.out.println(name+":"+"pname=" + pname + ", page=" + page +","+ address);
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }
    
}
public class Address {
    private String provices;
    private String city;
    public void setAddress(String provices,String city){
        this.provices = provices;
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address [provices=" + provices + ", city=" + city + "]";
    }
    
}

这是一个我们要进行赋值的原始类 Person。下面我们产生一个 Person 对象,并调用其 clone 方法复制一个新的对象。
注意:调用对象的 clone 方法,必须要让类实现 Cloneable 接口,并且覆写 clone 方法。
测试:

@Test
public void testShallowClone() throws Exception{
    Person p1 = new Person("zhangsan",21);
    p1.setAddress("湖北省", "武汉市");
    Person p2 = (Person) p1.clone();
    System.out.println("p1:"+p1);
    System.out.println("p1.getPname:"+p1.getPname().hashCode());
    
    System.out.println("p2:"+p2);
    System.out.println("p2.getPname:"+p2.getPname().hashCode());
    
    p1.display("p1");
    p2.display("p2");
    p2.setAddress("湖北省", "荆州市");
    System.out.println("将复制之后的对象地址修改:");
    p1.display("p1");
    p2.display("p2");
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

深拷贝

在这里插入图片描述
在这里插入图片描述

如何实现深拷贝?
  1. 让每个引用类型属性内部都重写clone() 方法
  2. 利用序列化
1 原型模式介绍

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

西游记中的孙悟空 拔毛变小猴,孙悟空这种根据自己的形状复制出多个身外化身的技巧,在面向对象软件设计领域被称为原型模式.孙悟空就是原型对象.
在这里插入图片描述
在这里插入图片描述

2 原型模式原理

在这里插入图片描述
在这里插入图片描述

3 深克隆与浅克隆

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3) 浅克隆代码实现:

在这里插入图片描述
测试

@Test
public void test01() throws CloneNotSupportedException {
	ConcretePrototype c1 = new ConcretePrototype();
	ConcretePrototype c2 = c1.clone();
	//输出false
	System.out.println("对象c1和c2是同一个对象?" + (c1==c2));
}
4) 深克隆代码实现
/**
 * 具体原型类
 * 实现Cloneable标识接口,表示当前类对象可复制
 **/
public class ConcretePrototype implements Cloneable, Serializable {

    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public void show(){
        System.out.println("嫌疑人姓名: " + person.getName());
    }

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

    @Override
    protected ConcretePrototype clone() throws CloneNotSupportedException {
        System.out.println("克隆对象复制成功!");
        return (ConcretePrototype) super.clone();
    }
}
import java.io.Serializable;

public class Person implements Serializable {

    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
//浅拷贝
    @Test
    public void test02() throws CloneNotSupportedException {

        ConcretePrototype c1 = new ConcretePrototype();
        Person p1 = new Person("峰哥");
        c1.setPerson(p1);

        //复制c1
        ConcretePrototype c2 = c1.clone();
        Person p2 = c2.getPerson();
        p2.setName("凡哥");

        c1.show();
        c2.show();
        //输出true,克隆对象和原型对象还是共享name属性的
        System.out.println("对象p1和对象p2是同一个对象吗?" + (p1 == p2));
    }

如果有需求场景中不允许共享同一对象,那么就需要使用深拷贝,如果想要进行深拷贝需要使用到对象序列化流 (对象序列化之后,再进行反序列化获取到的是不同对象).
在这里插入图片描述

4 原型模式应用实例

在这里插入图片描述
在这里插入图片描述

代码实现
广告模板代码
/**
 * 广告模板
 **/
public class AdvTemplate {

    //广告信名称
    private String advSubject = "xx银行本月还款达标,可抽iPhone 13等好礼!";

    //广告信内容
    private String advContext = "达标用户请在2022年3月1日到2022年3月30日参与抽奖......";

    public String getAdvSubject() {
        return advSubject;
    }

    public void setAdvSubject(String advSubject) {
        this.advSubject = advSubject;
    }

    public String getAdvContext() {
        return advContext;
    }

    public void setAdvContext(String advContext) {
        this.advContext = advContext;
    }
}

邮件类代码

/**
 * 邮件类
 **/
public class Mail {

    private String receiver; //收件人

    private String subject; //邮件名称

    private String appellation; //称呼

    private String context;  //邮件内容

    private String tail; //邮件尾部 "xx版权所有"

    public Mail(AdvTemplate advTemplate) {
        this.subject = advTemplate.getAdvSubject();
        this.context = advTemplate.getAdvContext();
    }

    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getAppellation() {
        return appellation;
    }

    public void setAppellation(String appellation) {
        this.appellation = appellation;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }
}

客户类

/**
 * 业务场景
 **/
public class Client {

    //发送邮件的数量
    private static int MAX_COUNT = 6;

    //发送邮件
    public static void sendMail(Mail mail){
        System.out.println("标题: " + mail.getSubject() + "\t 收件人: " + mail.getReceiver()
        + "\t ...发送成功!");
    }

    public static void main(String[] args) {

        int i = 0;

        //定义模板
        Mail mail = new Mail(new AdvTemplate());
        mail.setTail("xxx银行版权所有");
        while(i < MAX_COUNT){
            //每封邮件不同的信息
            mail.setAppellation(" 先生 (女士)");
            Random random = new Random();
            int num = random.nextInt(999999999);
            mail.setReceiver(num + "@"+"mashibing.com");

            //发送邮件
            sendMail(mail);
            i++;
        }
    }

}

在这里插入图片描述
代码重构
Mail类

public class Mail implements Cloneable {

    private String receiver; //收件人

    private String subject; //邮件名称

    private String appellation; //称呼

    private String context;  //邮件内容

    private String tail; //邮件尾部 "xx版权所有"

    public Mail(AdvTemplate advTemplate) {
        this.subject = advTemplate.getAdvSubject();
        this.context = advTemplate.getAdvContext();
    }

    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getAppellation() {
        return appellation;
    }

    public void setAppellation(String appellation) {
        this.appellation = appellation;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }

    @Override
    protected Mail clone() {
        Mail mail = null;

        try {
            return  (Mail)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Client类

public class Client {

    //发送邮件的数量
    private static int MAX_COUNT = 6;

    //发送邮件
    public static void sendMail(Mail mail){
        System.out.println("标题: " + mail.getSubject() + "\t 收件人: " + mail.getReceiver()
                + "\t ...发送成功!");
    }

    public static void main(String[] args) {

        int i = 0;

        //定义模板
        Mail mail = new Mail(new AdvTemplate());
        mail.setTail("xxx银行版权所有");

        while(i < MAX_COUNT){
            //每封邮件不同的信息
            Mail cloneMail = mail.clone();
            cloneMail.setAppellation(" 先生 (女士)");
            Random random = new Random();
            int num = random.nextInt(999999999);
            cloneMail.setReceiver(num + "@"+"mashibing.com");

            //发送邮件
            sendMail(cloneMail);
            i++;
        }
    }
}
5 原型模式总结

原型模式的优点:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
原型模式缺点:
需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时需要修改源代码,违背了开闭原则.

使用场景

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1125135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python安装.whl文件

python --version https://www.lfd.uci.edu/~gohlke/pythonlibs/ 用CtrlF找需要安装的包 下载对应版本的whl python3.8 把下载好的whl放到安装路径下&#xff1a;C:\Users\Administrator\AppData\Local\Programs\Python\Python38\Lib\site-packages 并在该路径下打开cmd执行…

GaussDB数据库管理系统介绍

1.GaussDB的发展 2.GaussDB的生态 内部&#xff1a; 云化自动化方案。通过数据库运行基础设施的云化将DBA(数据库管理员)和运维人员的日常工作 自动化。外部&#xff1a; 采用与数据库周边生态伙伴对接与认证的生态连接融合方案&#xff0c;解决开发者/DBA难获取、应用难对接等…

Linux绝对路径和相对路径

在 Linux 中&#xff0c;简单的理解一个文件的路径&#xff0c;指的就是该文件存放的位置。 只要我们告诉 Linux 系统某个文件存放的准确位置&#xff0c;那么它就可以找到这个文件。指明一个文件存放的位置&#xff0c;有 2 种方法&#xff0c;分别是使用绝对路径和相对路径。…

【驱动开发】LED灯的亮灭——通过字符设备驱动的分步实现编写LED驱动,实现设备文件和设备的绑定

头文件&#xff1a; #ifndef __HEAD_H__ #define __HEAD_H__typedef struct {unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t;//LED灯的寄存器地址 #define LED1_ADDR 0X50006000 #define L…

深入理解Redis集群模式、协议、元数据维护方式

文章目录 &#x1f34a; 集群模式&#x1f34a; 集群协议&#x1f34a; 元数据维护方式&#x1f389; 集中式&#x1f389; gossip 协议 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出…

适用于 Linux 和 Unix 的特权访问管理

凭据、SSH 密钥、服务帐户、数字签名、文件系统等内容构成了Linux 环境的关键部分&#xff0c;虽然大多数PAM供应商为基于Windows的环境提供无缝的特权访问管理&#xff0c;但它们的通用性不足以为Linux&#xff0c;Unix和*nix环境扩展相同的功能和功能。 Linux 中的root权限是…

redis的key超时策略和key淘汰机制(面试题详解)

ChatGPT给出的回答&#xff1a; Redis中的Key超时策略和Key淘汰机制是为了有效管理内存和控制数据的生命周期。 Key超时策略&#xff1a;Redis可以为每个Key设置过期时间&#xff0c;一旦Key过期&#xff0c;它将自动从Redis中删除。可以使用EXPIRE命令为Key设置过期时间&…

系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第六部分:开发运维

本心、输入输出、结果 文章目录 系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第六部分&#xff1a;开发运维前言DevOps vs. SRE vs. Platform Engineering。有什么区别&#xff1f;什么是k8s&#xff08;Kubernetes&#xff09;&#xff1f;控制面板组件节点 Docker vs…

关于阿里云服务器续费详细流程_优惠续费方法

阿里云服务器如何续费&#xff1f;续费流程来了&#xff0c;在云服务器ECS管理控制台选择续费实例、续费时长和续费优惠券&#xff0c;然后提交订单&#xff0c;分分钟即可完成阿里云服务器续费流程&#xff0c;阿里云服务器网分享阿里云服务器详细续费方法&#xff0c;看这一篇…

【代码随想录】算法训练营 第十三天 第五章 栈与队列 Part 3

239. 滑动窗口最大值 题目 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 思路 一开始我是直接暴力两层循环的&#xff…

Python学习笔记——MYSQL,SQL核心

食用说明&#xff1a;本笔记适用于有一定编程基础的伙伴们。希望有助于各位&#xff01; SQL语言分类 SQL注释 库管理 表管理 数据操作 分组聚合 分页限制 需要注意的是关键字的顺序不可以错乱&#xff0c;否则会报错其中LIMIT关键字的n是指从第n个开始&#xff0c;m是指查…

http post协议实现简单的rpc协议,WireShark抓包分析

文章目录 1.http 客户端-RPC客户端1.http 服务端-RPC服务端3.WireShark抓包分析3.1客户端到服务端的HTTP/JSON报文3.2服务端到客户端的HTTP/JSON报文 1.http 客户端-RPC客户端 import json import requests# 定义 RPC 客户端类 class RPCClient:def __init__(self, server_url…

【蓝桥杯选拔赛真题43】python二进制位数 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python二进制位数 一、题目要求 1、编程实现 2、输入输出 二、算法分析

深入浅出Apache SeaTunnel SQL Server Sink Connector

在大数据时代&#xff0c;数据的迁移和流动已经变得日益重要。为了使数据能够更加高效地从一个源流向另一个目标&#xff0c;我们需要可靠、高效和易于配置的工具。今天&#xff0c;我们将介绍 JDBC SQL Server Sink Connector&#xff0c;这是一个专为 SQL Server 设计的连接器…

嵌入式linux总线设备驱动模型分析

嵌入式linux系统按照&#xff0c;分层&#xff0c;抽象的思想&#xff0c;按照这样的思想来设计我们的程序可以更容易写出耦合性低、独立性强、可重用性强的代码。 Linux内核中更是存在着更多的分离、分层思想的代码&#xff0c;platform平台设备驱动就是用了这样的思想。本篇…

机器学习(新手入门)-线性回归 #房价预测

题目&#xff1a;给定数据集dataSet&#xff0c;每一行代表一组数据记录,每组数据记录中&#xff0c;第一个值为房屋面积&#xff08;单位&#xff1a;平方英尺&#xff09;&#xff0c;第二个值为房屋中的房间数&#xff0c;第三个值为房价&#xff08;单位&#xff1a;千美元…

pv操作题目笔记

对于 pv 操作分以下几步走 什么是pv操作 PV操作在进程同步中通常指的是信号量&#xff08;Semaphore&#xff09;操作。信号量是一种用于控制多个并发进程或线程之间的同步和互斥访问的同步工具。PV操作通常涉及两个基本操作&#xff1a;P操作&#xff08;wait操作&#xff0…

算法通关村第十一关青铜挑战——移位运算详解

大家好&#xff0c;我是怒码少年小码。 计算机到底是怎么处理数字的&#xff1f; 数字在计算机中的表示 机器数 一个数在计算机中的二进制表示形式&#xff0c;叫做这个数的机器数。 机器数是带符号的&#xff0c;在计算机用一个数的最高位存放符号&#xff0c;正数为0&am…

【剑指Offer】:删除链表中的倒数第N个节点(此题是LeetCode上面的)剑指Offer上面是链表中的倒数第K个节点

给定一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xff1a;…

计算机网路第3章-运输层

概述和运输层服务 运输层协议为运行在不同主机上的应用进程提供了逻辑通信&#xff0c;从应用程序角度看&#xff0c;通过使用逻辑通信&#xff0c;就好像运行在不同主机上的进程直接相连在一起一样。 运输层和网络层的关系 网络层提供主机之间的通信&#xff0c;而运输层提…