【创建型模式】原型模式

news2024/11/25 0:49:51

一、原型模式概述

        原型(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();
		}

}

三、代码结构图

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

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

相关文章

flask 应用程序

flask 程序示例 创建 hello.py 文件: # 导入 Flask 模块。Flask 类的一个对象是 wsgi 应用程序。 from flask import Flask# 创建app对象, Flask构造函数将当前模块的名称(__name__)作为参数。 app Flask(__name__)# route() 函数是一个装饰器,它告诉应…

使用Docker部署Node.js

第一步:在Node.js项目的根目录中新建Dockerfile文件 # 使用官方 Node.js 镜像作为基础镜像 FROM node:latest# 设置工作目录 WORKDIR /usr/src/app# 将项目文件复制到容器中 COPY . .# 将npm源设置为淘宝镜像 RUN npm config set registry https://registry.npmmir…

LeetCode-热题100:101. 对称二叉树

题目描述 给你一个二叉树的根节点 root , 检查它是否轴对称。 示例 1: 输入: root [1,2,2,3,4,4,3] 输出: true 示例 2: 输入: root [1,2,2,null,3,null,3] 输出: false 提示:…

【UE 材质】表面湿润效果

效果 步骤 1. 创建一个材质函数,这里命名为“MF_Weather_Wetness”,打开材质函数添加如下节点 其中输入的默认值分别为: 其中,“Desaturation”节点用于控制饱和度,我们通过给“Fraction”引脚输入一个负值来增加饱和…

个人可以做视频号小店吗?当然可以,但我建议这么做

大家好,我是电商笨笨熊 视频号小店在推出之后就吸引了不少的玩家, 这其中有很多之前做过电商的老玩家,甚至是团队,也有很多是一个人,刚开始做电商的新手小白。 对于电商老玩家来说,做过的可能会更容易上…

正交实验设计及数据处理

文章目录 一、正交实验基础知识介绍1.1 认识正交表1.2 正交表的特点1.3 正交表的分类 二、数据分析 本次内容参考自高等教育本科教材《实验设计与数据处理》 一、正交实验基础知识介绍 1.1 认识正交表 先看一组正交表的构造 这个表的题头代表了这个表的构造,其中…

DRAM发展史

DRAM(Dynamic Random Access Memory,动态随机存取存储器)自其发明以来,历经半个多世纪的发展,已成为现代计算机系统中不可或缺的关键组件。 诞生与早期发展 1966年:IBM公司的罗伯特登纳德(Robert H. Dennard)发明了DRAM。这种新型存储器利用一个晶体管和一个电容器组…

为什么Linus不把国家反诈中心加入Linux内核?

所谓的反诈和反诈 app 都是应用层面的事儿吧。这些东西如果真要集成,也是集成到浏览器中(监视你访问的内容和浏览记录),拨号和短信应用中(监视通话和短信)。还有微信之类的早就集成反诈了。如果你反复向一个…

Web3技术简介:重新定义互联网的未来

引言 在21世纪的数字时代,互联网已成为我们日常生活的不可或缺的一部分。然而,随着区块链和加密技术的快速发展,一个全新的互联网模型——Web3,正逐渐崭露头角。Web3不仅仅是技术的进步,它更是对传统互联网模型的挑战…

亚马逊测评自养号策略:手机与PC结合的重要性

亚马逊测评的核心关键技术在于精心培养买家账号,之所以称之为核心关键,原因在于测评下单的首要条件是拥有一个活跃的买家账号。买家账号并非一次性使用,因此,养号过程显得至关重要。然而,在养号的过程中,很…

sklearn中决策树算法实例--泰坦尼克号人员生存预测

目录 数据集 题目 算法步骤 数据集 下载地址 titanic.csv Yuyi Ye/ML-Decision-Tree - 码云 - 开源中国 (gitee.com) 题目 根据数据集中的数据,预测哪些乘客可以从泰坦尼克号沉船事故中幸免。 算法步骤 import pandas as pd import numpy as np from skle…

AI预测福彩3D第39弹【2024年4月18日预测--第8套算法开始计算第7次测试】

今天咱们继续测试第8套算法和模型,今天是第7次测试,目前的测试只是为了记录和验证,为后续的模型修改和参数调整做铺垫,所以暂时不建议大家盲目跟买~废话不多说了,直接上结果! 2024年4月18日3D的七码预测结果…

win7录屏功能在哪里?这篇文章告诉你答案

Windows 7作为微软公司推出的一款经典操作系统,虽然目前已经逐渐退出主流市场,但依然有许多用户对其情有独钟。在日常使用中,录屏功能是一个非常重要的工具,可以帮助我们记录下电脑屏幕上的操作过程,便于分享、教学或制…

从小到大输出四个整数(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int a, b, c, d;int t 0;//提示用户&#xff1b;printf("请输入四个整数a b c d&…

jenkins 部署 vue 项目

jenkins 部署 vue 项目 环境 系统&#xff1a;CentOS7.9 Jenkins&#xff1a;最新LTS版本 nginx: 1.24.x gitLab: 打包机&#xff1a;jenkins所在服务器 目标机器&#xff1a;nginx所在服务器 jenkins部署配置 关键脚本 #node -v #已经安装node_module就无需执行install安…

cesium 解决带高度的polygon 材质不能透明的问题

问题描述&#xff1a;创建一个带高度的polygon&#xff0c;用一个带透明度的图片做材质&#xff0c;画出来的多边形没有透明效果&#xff0c;图片的透明通道没有用上。 一、创建不带高度polygon 不带高度的polygon&#xff0c;使用带透明度的图片是有效果的&#xff0c;但是不…

2010年认证杯SPSSPRO杯数学建模A题(第一阶段)聪明的汽车全过程文档及程序

2010年认证杯SPSSPRO杯数学建模 A题 聪明的汽车 原题再现&#xff1a; 在狭窄的空间里把车停放在合适的位置&#xff0c;或在短小的停车位上侧位停车&#xff0c;一直是考验驾驶员技术与信心的问题。有调查报告称&#xff1a;57% 的驾驶员对自己的停车技术缺乏自信&#xff0…

【C++核心】面向对象的三大特性

面向对象的三大特性 一、封装性1. 封装性的意义1.1 表现事物1.2 权限控制1.3 成员属性设置为私有 2. 封装性的衍生知识2.1 struct和class区别2.2 友元2.2.1 全局函数做友元2.2.2 类做友元2.2.3 成员函数做友元 二、继承性1. 继承的语法2. 继承方式3. 继承中的对象模型3.1 说明3…

良友:献上今天(打开心窗说亮话)- 情绪的秘密

目录 一 二 三 四 五 六 七 八 九 十 十一 十二 十三