【创建型模式】原型模式

一、原型模式概述

        原型(Prototype)模式的定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。(对象创建型)

  •  工作原理
    • 将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程。
    • 创建新对象(也称克隆对象)的工厂就是原型类自身,工厂方法由负责复制原型对象的克隆方法来实现。
    • 通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,每个克隆对象都是独立的。
    • 通过不同的方式对克隆对象进行修改以后,可以得到一系列相似但不完全相同的对象。
  • 浅克隆与深克隆
    • 浅克隆:当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
    • ​深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
  • 原型管理器
    • 将多个原型对象存储在一个集合中提供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得。
  • 原型模式的优缺点
    • 优点
      • 1.简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率;
      • 2.扩展性好;
      • 3.提供了简化的创建结构,原型模式中的产品的复制时通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品;
      • 4.可以使用深克隆的方式保存对象的状态,以便在需要的时候使用,可辅助实现撤销操作。
    • 缺点
      • 1.需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当已有对象的类进行改造时们需要修改源代码,违背了开闭原则;
      • 2.在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应得类都必须支持深克隆,实现起来可能会比较麻烦。
  • 适用环境
    • 1.创建新对象成本比较大,新对象可以通过复制已有对象来获得,如果相似对象,则可以对其成员变量稍作修改;
    • 2.系统要保存对象得状态,而对象得状态变化很小;
    • 3.需要便面使用分层次得工厂类来创建分层次得对象;
    • 4.ctrl+c->ctrl+v。

二、代码实现

        原型模式包含三个角色:

  • 访问类(客户类):提出创建对象的请求,使用具体原型类中的 clone() 方法来复制新的对象。
  • 抽象原型(Prototype)角色:此角色定义了的具体原型类所需的实现的方法。也就是定义一个文件,说明一下它有被克隆复制的功能。
  • 具体原型(Concrete Prototype)角色:实现抽象原型角色的克隆接口。就是我们的文件实现了可以被复制的功能。

        我们会发现其实原型模式的核心就是Prototype(抽象原型),他需要继承Cloneable接口,并且重写Object类中的clone方法才能有复制粘贴的功能。

2.1 demo

        2.1.1 抽象原型角色
package prototype.demo;
//抽象原型角色
public interface Prototype {
	public Prototype clone();
}
        2.1.2 具体原型角色
package prototype.demo;
//具体原型角色
public class ConcretePrototype implements Prototype{
	private int dataInt=1;
	private A dataA=new A();
	public String toString() {
		return "ConcretePrototype"+"["+",dataInt"+dataInt
				+",dataA_address="+dataA
				+",dataA="+dataA.getChar_a()+
	"]";
	}
	public int getDataInt() {
		return dataInt;
	}
	public void setDataInt(int dataInt) {
		this.dataInt = dataInt;
	}
	public A getDataA() {
		return dataA;
	}
	public void setDataA(A dataA) {
		this.dataA = dataA;
	}
	//克隆方法 shallow
	public Prototype clone() {
		ConcretePrototype copy=new ConcretePrototype();
		copy.setDataInt(this.getDataInt());
		copy.setDataA(this.getDataA());
		return copy;
	}
	//克隆方法 deep
	public Prototype clone2() {
		ConcretePrototype copy=new ConcretePrototype();
		copy.setDataInt(this.getDataInt());
		A ta=new A();
		ta.setChar_a(this.getDataA().getChar_a());
		copy.setDataA(this.getDataA());
		return copy;
	}
	
}
package prototype.demo;
//封装的方法
public class A {
	char char_a;

	public char getChar_a() {
		return char_a;
	}

	public void setChar_a(char char_a) {
		this.char_a = char_a;
	}
	public A(char char_a) {
		super();
		this.char_a=char_a;
	}
	public A() {
		this.char_a='a';
	}
}
        2.1.3 main方法实现原型模式(Client)
package prototype.demo;

public class Client {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		/*ConcretePrototype p=new ConcretePrototype();
		ConcretePrototype copy=(ConcretePrototype) p.clone();
		ConcretePrototype copy2=(ConcretePrototype) p.clone();
		System.out.println(p.toString());
		System.out.println(copy.toString());
		System.out.println(copy2.toString());
		
		copy.setDataInt(2);
		A a=new A('b');
		copy.setDataA(a);
		System.out.println("-------------------------------");
		System.out.println(p.toString());
		System.out.println(copy.toString());
		System.out.println(copy2.toString());*/
		ConcretePrototype p=new ConcretePrototype();
		ConcretePrototype copy=(ConcretePrototype) p.clone2();
		ConcretePrototype copy2=(ConcretePrototype) p.clone2();
		System.out.println(p.toString());
		System.out.println(copy.toString());
		System.out.println(copy2.toString());
		
		copy.setDataInt(2);
		A a=new A('b');
		copy.setDataA(a);
		System.out.println("-------------------------------");
		System.out.println(p.toString());
		System.out.println(copy.toString());
		System.out.println(copy2.toString());
	}

}
        2.4 UML图

2.2 浅克隆

        2.2.1 抽象原型角色

        java.io.Serializable这个接口。

        2.2.2 具体原型角色
package prototype.deepclone;

import java.io.Serializable;
//实现了Serializable这个接口
public class Attachment implements Serializable{
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	public void download() {
		System.out.println("下载附件,文件名为:"+name);
	}
}
package prototype.shallowclone;

public class WeeklyLog implements Cloneable{
	//简化设计,定义一个附件
	private Attachment attachment;
	private String name;
	private String date;
	private String content;
	public Attachment getAttachment() {
		return attachment;
	}
	public void setAttachment(Attachment attachment) {
		this.attachment = attachment;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	//使用clone()方法实现浅克隆
	@Override
	protected WeeklyLog clone(){
		// TODO 自动生成的方法存根
		try {
			return (WeeklyLog)super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
			return null;
		}	
	}
	
}
        2.2.3 Client
package prototype.shallowclone;

public class Client {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		WeeklyLog obj=new WeeklyLog();
		Attachment att=new Attachment();
		att.setName("obj");
		obj.setAttachment(att);
		
		WeeklyLog copy=obj.clone();
		obj.getAttachment().download();
		copy.getAttachment().download();
	}

}

2.3 深克隆

        2.2.1 抽象原型角色

        java.io.Serializable这个接口。

        2.2.2 具体原型角色
package prototype.deepclone;

import java.io.Serializable;
//实现了Serializable这个接口
public class Attachment implements Serializable{
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	public void download() {
		System.out.println("下载附件,文件名为:"+name);
	}
}
package prototype.deepclone;

import java.io.*;

public class WeeklyLog implements Serializable{
	//简化设计,定义一个附件
	private Attachment attachment;
	private String name;
	private String date;
	private String content;
	public Attachment getAttachment() {
		return attachment;
	}
	public void setAttachment(Attachment attachment) {
		this.attachment = attachment;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	//使用序列化技术实现克隆
	protected WeeklyLog deepClone() throws IOException,ClassNotFoundException{
		// TODO 自动生成的方法存根
		//将对象写入流中
		ByteArrayOutputStream bao=new ByteArrayOutputStream();
		ObjectOutputStream oos=new ObjectOutputStream(bao);
		oos.writeObject(this);
		//将对象从流中取出
		ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
		ObjectInputStream ois=new ObjectInputStream(bis);
		return (WeeklyLog)ois.readObject();
	}
	
}
        2.2.3 Client
package prototype.deepclone;

public class Client {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		WeeklyLog log_previous,log_new=null;
		log_previous=new WeeklyLog();//创建原型对象
		Attachment attachment=new Attachment();//创建附件对象
		attachment.setName("aaa");
		log_previous.setAttachment(attachment);//将附件添加到周报中
		try {
			log_new=log_previous.deepClone();//调用深克隆方法
		}catch(Exception e) {
			System.out.println("克隆失败!");
		}
		//比较周报
		System.out.println("周报是否相同?"+(log_previous==log_new));
		//比较附件
		System.out.println("附件是否相同?"+(log_previous.getAttachment()==log_new.getAttachment()));
		log_previous.getAttachment().download();
		log_new.getAttachment().download();
		}

}

三、代码结构图

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Qt】Qt安装包、源码、子模块(submodules)下载

1、Qt 4.0 ~ Qt5.14 Qt 4.0 ~ Qt5.14 离线安装包、源码和子模块(submodules)源码下载路径: https://download.qt.io/new_archive/qt/以Qt5.7.1为例,注意子模块都是源码,需要独立编译 2、Qt5.15 ~ Qt6.7 Qt5.15 ~ Qt6.7源码和子模块(submodules)源码下载路径: htt…

分类算法——决策树(五)

认识决策树 决策树思想的来源非常朴素,程序设计中的条件分支结构就是if-else结构,最早的决策树就是利用这类结构分割数据的一种分类学习方法。 决策树分类原理详解 为了更好理解决策树具体怎么分类的,通过一个问题例子: 问题…

【MIT6.824】lab3 Fault-tolerant Key/Value Service 实现笔记

引言 lab3A的实验要求如下: Your first task is to implement a solution that works when there are no dropped messages, and no failed servers. You’ll need to add RPC-sending code to the Clerk Put/Append/Get methods in client.go, and implement Pu…

HiveSql中的函数家族(二)

一、窗口函数 1、什么是窗口函数 在 SQL 中,窗口函数(Window Functions)是一种特殊的函数,它允许在查询结果集的特定窗口(通常是一组行)上执行聚合、分析和计算操作,而无需聚合整个结果集。窗口…

使用Python工具库SnowNLP对评论数据标注(二)

这一次用pandas处理csv文件 comments.csv import pandas as pd from snownlp import SnowNLPdf pd.read_csv("C:\\Users\\zhour\\Documents\\comments.csv")#{a: [1, 2, 3], b: [4, 5, 6], c: [7, 8, 9]}是个字典 emotions[] for txt in df[sentence]:s SnowNLP(…

接收区块链的CCF会议--ICSOC 2024 截止7.24

ICSOC是CCF B类会议(软件工程/系统软件/程序设计语言) 2023年长文短文录用率22% Focus Area 4: Emerging Technologies Quantum Service Computing Digital Twins 3D Printing/additive Manufacturing Techniques Blockchain Robotic Process Autom…

【QT+OpenCV】车牌号检测 学习记录 遇到的问题

【QTOpenCV】车牌号检测 学习记录 首先在QT里面配置好OpenCV .pro文件中加入: INCLUDEPATH G:/opencv/build/include LIBS -L"G:/opencv/build/x64/vc14/lib"\-lopencv_core \-lopencv_imgproc \-lopencv_highgui \-lopencv_ml \-lopencv_video \-lo.c…

Meta Llama 3强势来袭:迄今最强开源大模型,性能媲美GPT-4

前言 Meta的最新语言模型Llama 3已经发布,标志着在大型语言模型(LLM)领域的一次重大突破,其性能在行业内与GPT-4相媲美。此次更新不仅提升了模型的处理能力和精确性,还将开源模型的性能推向了一个新的高度。 Huggingf…

Docker八股总结

1. 容器和虚拟机的区别 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容…

2021年全国大学生电子设计竞赛D题——基于互联网的摄像测量系统(二)

09 电路设计 前面介绍了系统的硬件框图如下: 硬件基本分为三块,两个摄像节点,一个终端节点。 1. 摄像节点硬件 摄像节点由一个DE10-Nano开发板和一个D8M摄像头实现,DE10-Nano开发板的HDMI接口外接HDMI显示器来显示拍摄到的视频。…

Flask + Bootstrap vs Flask + React/Vue:初学者指南

在这篇博客文章中,我们将比较 Flask Bootstrap 和 Flask React/Vue 这两种技术栈,以帮助初学者了解哪种组合更适合他们的项目需求。我们将从学习曲线、易用性、依赖管理、构建部署和路由定义等方面进行比较。 学习曲线 Flask 是一个基于 Python 的轻…

信息系统项目管理师0055:优化和持续改进(4信息系统管理—4.1管理方法—4.1.5优化和持续改进)

点击查看专栏目录 文章目录 4.1.5优化和持续改进1.定义阶段2.度量阶段3.分析阶段4.改进/设计阶段5.控制/验证阶段4.1.5优化和持续改进 优化和持续改进是信息系统管理活动中的一个环节,良好的优化和持续改进管理活动能够有效保障信息系统的性能和可用性等,延长整体系统的有效使…

偏微分方程算法之一阶双曲差分法

目录 一、研究目标 二、理论推导 2.1 引言 2.2 迎风格式 2.3 完全不稳定差分格式 2.4 蛙跳格式(Leapfrog) 2.5 Lax-Friedrichs格式 2.6 Lax-Wendroff格式 2.7 Beam-Warming格式 2.8 隐格式 2.9 Courant-Friedrichs-Lewy条件(CFL条…

一文学会时序约束

主时钟约束命令/生成时钟约束命令IO输入输出延迟约束命令及效果最大最小延迟命令及作用多周期路径怎么约束什么情况设置伪路径时钟组设置的三个选项 如果不了解时序分析可以先看下下面这篇文章: 数字IC/FPGA——时序分析 目录 1.时钟约束(1)…

线性代数---行列式的性质

1. 行列式的行与列(按原顺序)互换

redis的数据结构报错

文章目录 redis的数据结构报错Redis使用LocalDateTime报错问题 redis的数据结构报错 Redis使用LocalDateTime报错问题 SpringBoot整合Redis时,使用LocalDate以下报错 org.springframework.data.redis.serializer.SerializationException: Could not read JSON: C…

数字时代安全风险防范与保密科技创新

文章目录 前言一、新技术应用带来的保密挑战1.1 通过技术手段获取国家秘密和重要情报日益普遍1.2 新型信息技术存在的风险不容忽视 二、加强保密科技创新的必要性2.1 提高定密准确性2.2 及时变更密级或解密2.3 对失泄密事故案件进行自动高效的预警和初步处理 三、保密科技创新中…

Jenkins机器已经安装了ansible, 运行的时候却报错ansible: command not found

操作系统:MacOS Jenkins log提示 ansible: command not found 直接在Jenkins 机器中,进入一样的目录执行ansible --version OK 原因: Jenkins 默认使用的环境是 /usr/bin, 而我的ansible 安装配置在conda3 下面,所以需要在Jenkin…

OpenCV从入门到精通实战(四)——答题卡识别判卷系统

基于OpenCV的答题卡识别系统,其主要功能是自动读取并评分答题卡上的选择题答案。系统通过图像处理和计算机视觉技术,自动化地完成了从读取图像到输出成绩的整个流程。下面是该系统的主要步骤和实现细节的概述: 1. 导入必要的库 系统首先导入…

修改npm全局安装模式的路径

修改npm全局安装模式的路径 由于之前安装过nodejs,并且配置环境变量以及cache 、prefix 的信息; 由于项目需求安装最新版本的Nodejs,把环境变量的path相关目录进行调整,然后使用一下命令进行安装cnpm命令; npm insta…