原型模式详细介绍和代码实现

news2025/1/13 2:25:59

🎯 设计模式专栏,持续更新中, 欢迎订阅:JAVA实现设计模式
🛠️ 希望小伙伴们一键三连,有问题私信都会回复,或者在评论区直接发言

Java实现原型模式

介绍: 原型模式(Prototype Pattern)是一种创建型设计模式,允许通过复制已有对象来创建新对象,而不需要依赖其具体类。这种模式的关键在于克隆现有对象,而不是通过直接实例化新对象,从而避免重复的复杂对象构建过程。

🎯 案例场景:

假设我们在开发一个游戏角色系统,每个角色都有不同的属性,比如力量、敏捷和智力。创建一个新角色需要耗费大量的计算资源(如生成外貌、装备等)。如果我们想要快速创建一个与现有角色相似的新角色,只需要在原有角色基础上进行微调,而不重新生成所有属性。

我们可以使用原型模式,通过复制已有角色对象,再对其进行调整,来生成新的角色。

原型模式的核心步骤:

  1. Prototype 接口:定义 clone() 方法,所有需要被复制的对象实现该接口。
  2. 具体原型类:实现 clone() 方法,用于创建对象的副本。
  3. 客户端代码:通过调用 clone() 方法来复制已有对象。

🧑‍💻 Java代码实现:

在这里插入图片描述

import java.util.HashMap;
import java.util.Map;

// 1. 定义原型接口 Prototype
interface GameCharacter extends Cloneable {
    GameCharacter clone();
    void display();
}

// 2. 具体的角色类实现原型接口
class Warrior implements GameCharacter {
    private String name;
    private int strength;
    private int agility;
    private int intelligence;

    public Warrior(String name, int strength, int agility, int intelligence) {
        this.name = name;
        this.strength = strength;
        this.agility = agility;
        this.intelligence = intelligence;
    }

    // 实现 clone 方法
    @Override
    public Warrior clone() {
        try {
            return (Warrior) super.clone();  // 调用 Object 类的 clone 方法
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Clone not supported", e);
        }
    }

    // 展示角色信息
    @Override
    public void display() {
        System.out.println("Warrior [Name: " + name + ", Strength: " + strength +
                ", Agility: " + agility + ", Intelligence: " + intelligence + "]");
    }
}

// 3. 客户端代码,使用原型模式
public class PrototypePatternDemo {
    public static void main(String[] args) {
        // 创建一个原始的角色
        Warrior originalWarrior = new Warrior("Arthas", 80, 50, 30);
        originalWarrior.display();

        // 使用克隆方法复制角色
        Warrior clonedWarrior = originalWarrior.clone();
        
        // 修改克隆对象的某些属性
        clonedWarrior.display();
        
        // 现在,原始角色和克隆角色的内存地址不同,但属性相同
        System.out.println("Original Warrior HashCode: " + originalWarrior.hashCode());
        System.out.println("Cloned Warrior HashCode: " + clonedWarrior.hashCode());
    }
}

📋 解释:

  1. GameCharacter 接口:定义了 clone() 方法,表示所有实现这个接口的类都可以被克隆。
  2. Warrior:实现了 GameCharacter 接口,并通过 super.clone() 进行浅克隆。这个方法通过复制对象的当前状态来创建一个新实例。
  3. 客户端代码:首先创建了一个 Warrior 对象 originalWarrior,并使用其 clone() 方法创建了一个副本 clonedWarrior。然后可以自由修改克隆对象的属性,而不影响原始对象。

🌟 应用场景:

  1. 对象创建开销大,不希望每次都通过构造函数创建。
  2. 需要保存对象的初始状态,以便在不同地方进行修改和操作。
  3. 游戏开发中,需要频繁创建相似但稍有不同的角色或物品。

深拷贝和浅拷贝

浅拷贝:复制对象时,只复制对象的基本属性引用类型的引用。即如果对象的属性是引用类型(如数组、对象),浅拷贝只会复制这些引用,而不是引用所指向的实际对象。因此,拷贝后的对象和原始对象共享这些引用类型的数据,修改引用类型的内容会影响原始对象。

深拷贝:不仅会复制对象的基本属性,还会递归地复制引用类型所指向的对象,即引用对象也会完全复制成一个新的副本。这样,拷贝后的对象与原始对象完全独立,修改拷贝对象的引用类型内容,不会影响原始对象。

🌟 案例解释:

假设我们有一个 Person 类,里面包含基本类型属性 name 和引用类型 address

1. 浅拷贝示例:

浅拷贝只复制基本属性和引用对象的引用,不复制引用对象本身。

class Address {
    String city;

    public Address(String city) {
        this.city = city;
    }
}

class Person implements Cloneable {
    String name;
    Address address;

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

    // 浅拷贝
    @Override
    public Person clone() {
        try {
            return (Person) super.clone();  // 调用 Object 的 clone 方法
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Clone not supported", e);
        }
    }

    public void display() {
        System.out.println("Name: " + name + ", City: " + address.city);
    }
}

public class ShallowCopyDemo {
    public static void main(String[] args) {
        Address address = new Address("New York");
        Person person1 = new Person("John", address);
        Person person2 = person1.clone();  // 浅拷贝

        // 显示原始和克隆对象
        person1.display();  // Name: John, City: New York
        person2.display();  // Name: John, City: New York

        // 修改克隆对象的 address
        person2.address.city = "San Francisco";

        // 浅拷贝后,原始对象的 address 也被改变
        person1.display();  // Name: John, City: San Francisco
        person2.display();  // Name: John, City: San Francisco
    }
}

结果解释

  • person2person1 的浅拷贝。
  • person2address.city 修改为 "San Francisco" 后,person1address.city 也变成了 "San Francisco"。这是因为浅拷贝只复制了引用,两个对象共享同一个 Address 对象。
2. 深拷贝示例:

深拷贝需要复制所有对象,包括引用对象中的数据。

class Address implements Cloneable {
    String city;

    public Address(String city) {
        this.city = city;
    }

    @Override
    public Address clone() {
        try {
            return (Address) super.clone();  // 克隆 Address 对象
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Clone not supported", e);
        }
    }
}

class Person implements Cloneable {
    String name;
    Address address;

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

    // 深拷贝
    @Override
    public Person clone() {
        try {
            Person clonedPerson = (Person) super.clone();
            clonedPerson.address = address.clone();  // 深拷贝 Address
            return clonedPerson;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Clone not supported", e);
        }
    }

    public void display() {
        System.out.println("Name: " + name + ", City: " + address.city);
    }
}

public class DeepCopyDemo {
    public static void main(String[] args) {
        Address address = new Address("New York");
        Person person1 = new Person("John", address);
        Person person2 = person1.clone();  // 深拷贝

        // 显示原始和克隆对象
        person1.display();  // Name: John, City: New York
        person2.display();  // Name: John, City: New York

        // 修改克隆对象的 address
        person2.address.city = "San Francisco";

        // 深拷贝后,原始对象的 address 未被改变
        person1.display();  // Name: John, City: New York
        person2.display();  // Name: John, City: San Francisco
    }
}

结果解释

  • person2person1 的深拷贝。
  • person2address.city 修改为 "San Francisco" 后,person1address.city 仍然是 "New York"。这是因为深拷贝创建了 Address 对象的独立副本,两个对象不再共享同一个引用。

🔍 关键区别总结:

  1. 浅拷贝
    • 只复制对象的基本类型属性引用的地址,不复制引用的实际内容。
    • 拷贝后的对象与原对象共享引用类型的对象。
    • 如果修改了引用类型的数据,原始对象也会受到影响。
  2. 深拷贝
    • 复制对象的所有属性,包括递归复制引用类型对象
    • 拷贝后的对象和原始对象完全独立,互不影响。
    • 修改其中一个对象的引用类型内容,不会影响另一个对象。

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

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

相关文章

C4D2025来了!亮眼的新功能一览

C4D2025新功能亮点,同步上新的Redshift 2025.0.2。等我体验了再给大家讲详细的 成都渲染101云渲染支持对应软件渲染,3090等显卡,云渲码6666 渲染101云渲码6666 Mograph增强 引入线性域标签,用于精细控制对象参数。 为追踪器对象新…

安泰功率放大器有哪些特点呢

功率放大器是电子设备中的重要组成部分,其作用是将输入信号的电功率放大到足够的水平,以驱动负载,如扬声器或天线。功率放大器有一些独特的特点,这些特点对于各种应用至关重要。下面将详细介绍功率放大器的特点,以更好…

【Vue】移动端访问Vue项目页面无数据,但是PC访问有数据

问题: Vue项目,PC访问时下拉列表有数据,移动端访问时下拉列表没有数据; 思路: 首先打开了Fiddler抓包工具,把抓到的url复制到PC浏览器进行访问,结果发现PC上访问这个页面是有数据的&#xff…

利用Leaflet.js创建交互式地图:绘制固定尺寸的长方形

在现代Web开发中,交互式地图已成为展示地理位置数据的重要工具。Leaflet.js是一个轻量级、功能丰富的开源JavaScript库,用于构建移动友好的交互式地图。在本文中,我们将探讨如何利用Leaflet.js在地图上绘制一个固定尺寸的长方形,扩…

堆+堆排序+topK问题

目录 堆: 1、堆的概念 2、堆的结构 3、堆的实现 3.1、建堆 3.1.1、向上调整建堆(用于堆的插入) 3.1.2、向下调整建堆 3.2、堆的删除 3.3、堆的代码实现 3.3.1、Heap.h 3.3.2、Heap.c 堆排序:(O(N*log(N))) 1、排序如何…

接口测试用例的编写

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 1、接口测试发现的典型问题 接口测试经常遇到的bug和问题,如下: 传入参数处理不当,导致程序crash类型溢出,导…

下载chromedriver驱动

首先进入关于ChromeDriver最新下载地址:Chrome for Testing availability 进入之后找到与自己所匹配的,在浏览器中查看版本号,下载版本号需要一致。 下载即可,解压,找到 直接放在pycharm下即可 因为在环境变量中早已配…

严重干扰的验证码识别系统源码分享

严重干扰的验证码识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comp…

领夹麦克风哪个品牌好?大疆、西圣、博雅无线麦克风在线测评

​随着科技的不断进步,越来越多的专业音频设备出现在大家的视野中,无线领夹麦克风就是其中之一,并且很多人在视频创作、直播等场景中都会进行选购。但是近些年来无线领夹麦克风市场较为复杂,很多质量不佳的产品混杂其中&#xff0…

安全生产许可证的重要性

在现代社会,安全生产许可证对于企业来说,不仅仅是一种法律要求,更是一种社会责任和企业形象的体现。本文将深入探讨安全生产许可证的重要性,以及它如何影响企业的长期发展和社会责任。 一、法律合规性的重要性 安全生产许可证是企…

Windows上指定盘符-安装WSL虚拟机(机械硬盘)

参考来自于教程1:史上最全的WSL安装教程 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/386590591#%E4%B8%80%E3%80%81%E5%AE%89%E8%A3%85WSL2.0 教程2:Windows 10: 将 WSL Linux 实例安装到 D 盘,做成移动硬盘绿色版也不在话下 - 知乎 (z…

那些网站需要使用OV SSL证书?怎么申请?

🔒 需要OV SSL证书的网站 🏢 企业网站 公司官网:展示公司信息、产品服务,增强信任度。 电子商务网站:处理在线交易,保护用户数据安全。 🏦 金融网站 银行网站:处理金融交易&#x…

SMB流量分析

SMB协议流量主要分为以下几个阶段 1、 tcp三次握手 2、会话建立(Negotiate Protocol): 客户端发送Negotiate Protocol Request ,其中包含客户端支持的smb协议版本列表以及SMB Header信息 服务端发送Negotiate Protocol Response,包含服务…

Springboot中自定义监听器

一、监听器模式图 二、监听器三要素 广播器:用来发布事件 事件:需要被传播的消息 监听器:一个对象对一个事件的发生做出反应,这个对象就是事件监听器 三、监听器的实现方式 1、实现自定义事件 自定义事件需要继承ApplicationEv…

Git学习尚硅谷(005 idea集成git)

尚硅谷Git入门到精通全套教程(涵盖GitHub\Gitee码云\GitLab) 总时长 4:52:00 共45P 此文章包含第27p-第p32的内容 文章目录 忽略特定文件在家目录里创建这个文件在.gitconfig文件里配置这个文件 配置IDEA定位到git程序进行添加文件初始化本地库添加单个…

yolov1到yolov5的发展

基础概念 1. YOLO简介 YOLO(You Only Look Once):是一种基于深度神经网络的对象识别和定位算法,其最大的特点是运行速度很快,可以用于实时系统。 2. 目标检测算法 RCNN:该系列算法实现主要为两个步骤&am…

数据结构排序——归并排序递归与非递归

基本思想: 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个…

CANopen协议的理解

本文的重点是对CANopen协议的理解,不是编程实现 参考链接 canopen快速入门 1cia301协议介绍_哔哩哔哩_bilibili CANopen是什么? CANopen通讯基础(上)_哔哩哔哩_bilibili CANopen概述 图1. CAN报文标准帧的格式 CAN的报文可简单…

50projects50days案例代码分析学习、效果,Html+CSS+JavaScript小案例

案例来源于:https://github.com/bradtraversy/50projects50days,部分资源需要科学上网加载使用,往后不再赘述。 合集链接,欢迎订阅: https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzkwODY2OTA5NA&actiongetal…

Invoke-Maldaptive:一款针对LDAP SearchFilter的安全分析工具

关于Invoke-Maldaptive MaLDAPtive 是一款针对LDAP SearchFilter的安全分析工具,旨在用于对LDAP SearchFilter 执行安全解析、混淆、反混淆和安全检测。 其基础是 100% 定制的 C# LDAP 解析器,该解析器处理标记化和语法树解析以及众多自定义属性&#x…