原型模式-克隆一个对象

news2024/10/6 0:33:35

 在开发一个界面的时候,里面有多个Button,这些对象的属性内容相似。如果一个个实例化Button对象,并设置其属性,那么代码量将会增多。

通过一个原型对象克隆出多个一模一样的对象,该模式被称为原型模式。

 图 原型模式

Prototype: 抽象原型类,是声名克隆方法的接口,也可以是具体原型类的公共父类。

ConcretePrototype:具体原型类,实现了克隆方法,在克隆方法中返回自己的一个克隆对象。

Client:客户类,让一个原型对象克隆自身从而创建一个新的对象。

public interface ButtonClone {

    ButtonClone cloneBtn();

}

public class Button implements ButtonClone{

    private Double width;
    private Double height;

    public Double getWidth() {
        return width;
    }

    public void setWidth(Double width) {
        this.width = width;
    }

    public Double getHeight() {
        return height;
    }

    public void setHeight(Double height) {
        this.height = height;
    }

    @Override
    public ButtonClone cloneBtn() {
        Button newBtn = new Button();
        newBtn.setHeight(this.height);
        newBtn.setWidth(this.width);
        return newBtn;
    }
}

1 浅克隆与深克隆

浅克隆,如果源对象的成员变量是值类型,将复制一份给克隆对象,如果源对象的成员变量是引用类型,则将引用对象的地址复制一份给对象。

深克隆,无论源对象的成员变量是值类型还是引用类型,都将复制一份给目标对象。

1.1 浅克隆

Java的Object类提供了一个clone()方法,可以将一个Java对象浅克隆。能实现克隆Java类必须实现一个标识接口Cloneable,表示这个类支持被复制。

public class ConcretePrototype implements Cloneable{

    private String name;

    private String type;

    private List<String> list = new ArrayList<>();

    public ConcretePrototype(String name, String type) {
        this.name = name;
        this.type = type;
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                ", list=" + list +
                '}';
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        ConcretePrototype prototype = new ConcretePrototype("实际类型", "浅克隆");
        System.out.println("prototype:" + prototype);
        Object clone = prototype.clone();
        System.out.println("clone:" + clone);

        prototype.list.add("hello");
        System.out.println("clone:" + clone);
    }

}

1.2 深克隆

深克隆,除了对象本身被复制外,对象所包含的所有成员变量也将被复制。在Java中,如果需要实现深克隆,可以通过序列化等方式来实现。需要实例化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

public class CusForm implements Serializable , Cloneable{

    private String name;
    private CusFile cusFile;

    public CusForm(String name, CusFile cusFile) {
        this.name = name;
        this.cusFile = cusFile;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
        CusForm cusForm = new CusForm("表单", new CusFile());
        System.out.println(cusForm);
        System.out.println(cusForm.clone()); //java浅克隆,对象成员变量直接复制地址
        CusForm deepCloneObj = cusForm.deepClone();
        System.out.println(deepCloneObj);

//        运行结果
//        CusForm{name='表单', cusFile=com.huangmingfu.prototype.deep.CusForm$CusFile@1b6d3586}
//        CusForm{name='表单', cusFile=com.huangmingfu.prototype.deep.CusForm$CusFile@1ddc4ec2}
//        CusForm{name='表单', cusFile=com.huangmingfu.prototype.deep.CusForm$CusFile@1b6d3586}
    }

    public CusForm deepClone() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(this);

        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
        return (CusForm) objectInputStream.readObject();
    }

    @Override
    public String toString() {
        return "CusForm{" +
                "name='" + name + '\'' +
                ", cusFile=" + cusFile +
                '}';
    }

    private static class CusFile implements Serializable{}
}

2 原型管理器

将多个原型对象存储在一个集合中供客户端使用,它是一个专门复制克隆对象的工厂。其中定义了一个集合用于存储原型对象。

图 原型管理器

public class DeepClone implements Serializable {
    public DeepClone deepClone()  {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(this);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            return (DeepClone)objectInputStream.readObject();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }
}

public class ConcreteA extends DeepClone{

    private final String name = "concreteA";

    @Override
    public String toString() {
        return "ConcreteA{" +
                "name='" + name + '\'' +
                '}' + super.toString();
    }

}

public class ConcreteB extends DeepClone{

    private final String name = "ConcreteB";

    @Override
    public String toString() {
        return "ConcreteB{" +
                "name='" + name + '\'' +
                '}' + super.toString();
    }
}

public class PrototypeManager {

    private final Map<Class<? extends DeepClone>,DeepClone> prototypeMap = new HashMap<>();
    private final Set<Class<? extends DeepClone>> classes = new HashSet<>();

    private PrototypeManager() {}

    private static class HolderClass {
        private final static PrototypeManager instance = new PrototypeManager();
    }

    public static PrototypeManager getInstance() {
        return HolderClass.instance;
    }

    public void addPrototype(DeepClone deepClone) {
        if (classes.add(deepClone.getClass())) {
            prototypeMap.put(deepClone.getClass(),deepClone);
        }
    }

    public DeepClone getClone(Class<? extends DeepClone> cls) {
        DeepClone deepClone = prototypeMap.get(cls);
        if (deepClone == null) {
            throw new RuntimeException("克隆体不存在");
        }
        return deepClone.deepClone();
    }

}

public class Client {

    public static void main(String[] args) {
        ConcreteA concreteA = new ConcreteA();
        ConcreteB concreteB = new ConcreteB();
        PrototypeManager prototypeManager = PrototypeManager.getInstance();

        System.out.println(concreteA);
        System.out.println(concreteB);

        prototypeManager.addPrototype(concreteA);
        prototypeManager.addPrototype(concreteB);
        System.out.println("克隆分割线---------------");
        DeepClone deepCloneA = prototypeManager.getClone(ConcreteA.class);
        DeepClone deepCloneB = prototypeManager.getClone(ConcreteB.class);

        System.out.println(deepCloneA);
        System.out.println(deepCloneB);

//        运行结果
//        ConcreteA{name='concreteA'}com.huangmingfu.prototype.manager.ConcreteA@1b6d3586
//        ConcreteB{name='ConcreteB'}com.huangmingfu.prototype.manager.ConcreteB@4554617c
//        克隆分割线---------------
//        ConcreteA{name='concreteA'}com.huangmingfu.prototype.manager.ConcreteA@30dae81
//        ConcreteB{name='ConcreteB'}com.huangmingfu.prototype.manager.ConcreteB@1b2c6ec2
    }

}

3 适用场景

当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建工厂,通过复制一个已有实例可以提高新实例的创建效率。

  1. 创建新对象成本较大。
  2. 对象的状态变化很小,且系统需要保存对象的状态时。
  3. 需要创建许多相似对象。

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

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

相关文章

Vue-Router相关理解3

路由跳转的replace方法 编程式路由导航&#xff08;不用<router-link></router-link>&#xff09; src/components/Banner.vue <template><div class"col-xs-offset-2 col-xs-8"><div class"page-header"><h2>Vue R…

Nginx配置白名单访问

一、背景 在项目运行的时候&#xff0c;需要设置特定的访问权限&#xff0c;以拒绝其他可能存在的恶意访问。 二、配置 2.1、关键字 允许访问关键字&#xff1a;allow 屏蔽访问关键字&#xff1a;deny 2.2、作用域 作用域如下&#xff1a; http&#xff1a;所有网站屏蔽I…

MATLAB算法-数据挖掘算法详解,

Matlab是一种功能强大的数据分析和数据挖掘工具,提供了丰富的数据挖掘算法和函数。下面将介绍一些最著名的数据挖掘算法,并提供相应的代码示例。 K均值聚类算法(K-means Clustering): K均值聚类是一种常用的无监督学习算法,用于将数据集划分为K个不同的簇。以下是在Matla…

ElasticSearch学习(1) 基础操作

目前使用的ES版本是7&#xff0c;借用下其他的文档。说明下ES的存储。 ES首先是index 对应的是数据库&#xff0c;7以前有type的概念&#xff0c;7没有type的概念&#xff0c;也就是说现在ES7 一个库(index)只有一个表(type)。 一个表(type)可以有多行(doc) 一行(doc)有多列…

上手vue2的学习笔记4之搭建vue环境

一、安装node环境 上手vue2的学习笔记2之安装nodejs和npm的踩坑经历 node -v //查看是否安装成功 npm -v //查看npm是否安装成功二、搭建vue项目环境 参考链接1&#xff1a;vue(2.0版本)安装步骤教程 参考链接2: MacOS 搭建一个vue项目(完整步骤) 1、安装vue2 npm install …

驱动程序设计 平台驱动、Linux内存映射、Linux中断、按键中断控制 7.13

平台驱动 模块驱动&#xff1a; 一对多管理&#xff0c;系统管理效率低 加载卸载方便 设备模型&#xff1a;分层分级的管理4个重要的组成部分&#xff1a;class device driver bus&#xff08;总线&#xff09;层级&#xff1a;kobj-->kset/kobj-->kset-->kset class…

资产管理简单实用技巧,让你告别加班!

资产管理系统在现代商业环境中扮演着关键的角色。随着企业资产规模的不断扩大和多样化&#xff0c;有效地管理和跟踪资产变得至关重要。 随着企业竞争的加剧和资产管理的重要性日益凸显&#xff0c;资产管理系统将继续在各行各业中发挥着不可或缺的作用。无论是生产设备、办公设…

BottomSheetDialog无法设置圆角的解决问题

1、设置background为透明 <style name"BottomSheetDialog" parent"Theme.Design.Light.BottomSheetDialog"><item name"bottomSheetStyle">style/bottomSheetStyleWrapper</item></style><style name"bottomShe…

Redis的缓存问题

说起Redis的缓存&#xff0c;我们知道前端发出的请求到后端&#xff0c;后端先从Redis中查询&#xff0c;如果查询到了则直接返回&#xff0c;如果Redis中未查询到&#xff0c;就去数据库中查询&#xff0c;如果数据库中存在&#xff0c;则返回结果并且更新到Redis缓存当中&…

西贝柳斯Sibelius2023旗舰版曲谱大师必备音乐软件

乐谱太复杂&#xff0c;打起来太费时间&#xff1f;革命性的省时功能&#xff0c;如磁性布局和动态分谱&#xff0c;能够快速创作复杂的乐谱。音色库太简陋&#xff0c;找起来麻烦&#xff1f;收藏丰富的音色库供您直接使用&#xff0c;涵盖最广泛的专业级乐器&#xff0c;支持…

RK3399/RK3588+pcie+Zynq 多核架构可穿戴设备设计方案

在很多领域&#xff0c;人们对可穿戴设备的可靠性有着非常高的要求。这些使用场景 不仅丰富多样&#xff0c;而且复杂多变。这使得可穿戴设备不仅需要应对应用和系统本身 的状态变化&#xff0c;也要考虑到设备所处环境所带来的异常情况。所以&#xff0c;针对不同安全 等级…

Windows搭建SVN环境

VisualSVN Server下载 https://www.visualsvn.com/products VisualSVN Server安装创建仓库创建项目创建用户创建组项目分配组VisualSVN下载 https://www.visualsvn.com/products VisualSVN安装项目检出项目检出路径&#xff1a;https://changwq:8443/svn/dev/InterfaceManage 项…

【C++初阶】类和对象(上)

文章目录 前言一、类的引入二、类的定义三、类的访问限定符及封装四、类的作用域五、类的实例化六、类对象模型七、this指针 前言 &#x1f4d6;面向过程 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。以…

linux之Ubuntu系列(-)常见指令

Ubuntu 中文 版本 注意点 通过修改语言改成英文 在终端录入&#xff1a;export LANGen_US 在终端录入&#xff1a;xdg-user-dirs-gtk-update 单用户和多用户 命令格式 command [-选项] [参数] –查看命令的帮助 命令 --help man 命令 |操作键| 功能| |空格键|-显示手册的下…

[LINUX]之字符串去掉前后空格

去掉字符串前后空格通过使用awk $1$1命令实现 echo " test " | awk $1$1

Vulnhub: Momentum: 1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.154 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.154 查看目标80端口的main.js发现信息 feroxbuster -k -d 1 --url http://192.168.111.154 -w /opt/zidian/SecLists-202…

白名单配置

白名单配置 关于如何将github-copilot 相关地址设置到白名单中 domain:githubusercontent.com, domain:example-example.com, domain:example-example2.com 选择配置 绕过白名单 结尾 记录自己点点滴滴&#xff0c;学习总结

二叉树题目:二叉树的最大深度

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;二叉树的最大深度 出处&#xff1a;104. 二叉树的最大深度 难度 3 级 题目描述 要求 给定一个二叉树&#xff…

(ceph)CephFS 文件系统 MDS接口

创建 CephFS 文件系统 MDS 接口 //服务端操作 1&#xff09;在管理节点创建 mds 服务 cd /etc/ceph ceph-deploy mds create node01 node02 node032&#xff09;查看各个节点的 mds 服务 ssh rootnode01 systemctl status ceph-mdsnode01 ssh rootnode02 systemctl status cep…

定时器处理非活动连接(五)

1 基础知识 非活跃&#xff0c;是指客户端&#xff08;这里是浏览器&#xff09;与服务器端建立连接后&#xff0c;长时间不交换数据&#xff0c;一直占用服务器端的文件描述符&#xff0c;导致连接资源的浪费。 非活跃&#xff0c;是指固定一段时间之后触发某段代码&#xf…