【创建型模式】原型模式

一、原型模式概述

        原型(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;}//克隆方法 shallowpublic Prototype clone() {ConcretePrototype copy=new ConcretePrototype();copy.setDataInt(this.getDataInt());copy.setDataA(this.getDataA());return copy;}//克隆方法 deeppublic 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()方法实现浅克隆@Overrideprotected 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.hqwc.cn/news/630850.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis的RedisObject和对外可见的5种数据结构

目录 RedisObject Redis的编码方式 对外可见的5种数据结构 1.string string结构的源码 为什么是小于44字节会采用embstr编码? embstr和raw区别 2.list list结构的源码 3.set set结构的源码 4.zset zset结构的源码 5.hash hash结构的源码 Redis中…

yolov7模型输出层预测方法解读

本文从代码的角度分析模型训练阶段输出层的预测包括以下几个方面: 标注数据(下文统称targets)的正样本分配策略,代码实现位于find_3_positive。候选框的生成,会介绍输出层的预测值、GT、grid、 anchor之间的联系损失函…

Git使用总结(不断更新中)

branch 本地分支操作 删除本地分支 git branch -d <local-branch-name>远端分支操作 从远端分支创建本地分支 git checkout -b <local-branch-name> origin/<remote-branch-name>git ignore 如果工程的代码文件中有不希望上传到远端的文件&#xff0c;…

华为机考入门python3--(16)牛客16-购物单最大满意度

分类&#xff1a;动态规划&#xff0c;组合&#xff0c;最大值&#xff0c;装箱问题 知识点&#xff1a; 生成递减数 100, 90, 80, ..., 0 range(100, -1, -10) 访问列表的下标key for key, value in enumerate(my_list): 动态规划-捆绑装箱问题 a. 把有捆绑约束的物…

jvm中提前进入老年代

在JVM中&#xff0c;对象的“年龄”通常指的是对象经过了多少次Minor GC&#xff08;新生代垃圾回收&#xff09;后仍然存活。每次Minor GC后&#xff0c;存活的对象会被移动到Survivor区&#xff0c;并且它们的年龄会增加。当对象的年龄达到某个阈值&#xff08;这个阈值可以通…

uni-admin中引入uni-cms的缺少schema及uni-media-library缺少云函数的问题

1. 在管理端运行提示一些表找不到&#xff0c;因为是uni-admin关联的uni-starter的服务空间&#xff0c;在uni-admin的uniCloud中没有内容&#xff0c;在uni-starter的uniCloud中也没有发现对应的表&#xff0c;后面干脆在云端找到对应的表之后新建了&#xff0c;然后再下载到本…

Qt/C++音视频开发70-无感切换通道/无缝切换播放视频/多通道流畅切换/不同视频打开无缝切换

一、前言 之前就写过这个方案&#xff0c;当时做的是ffmpeg内核版本&#xff0c;由于ffmpeg内核解析都是代码实现&#xff0c;所以无缝切换非常完美&#xff0c;看不到丝毫的中间切换过程&#xff0c;看起来就像是在一个通道画面中。其实这种切换只能说是取巧办法&#xff0c;…

MySQL 锁机制全面解析

目录 1. MySQL的锁类型1.1 全局锁1.2 表锁1.3 行锁1.4 共享锁&#xff08;读锁&#xff09;1.5 排它锁&#xff08;写锁&#xff09;1.6 死锁 2 乐观锁和悲观锁2.1 乐观锁2.2 悲观锁 3 意向锁4 间隙锁5 临键锁6. 事务隔离级别对锁的影响6.1 读未提交&#xff08;Read Uncommitt…

二分法问题

日升时奋斗&#xff0c;日落时自省 目录 1、二分法 2、二分法问题 2.1 、在排序数组中查找元素的第一个和最后一个位置 2.2、搜索插入位置 2.3、山脉数组的峰顶索引 2.4、0-n-1中缺失的数字 1、二分法 二分法是比较简单的一种查找算法&#xff0c;但是效率很高&#xff0…

【运输层】TCP 的流量控制和拥塞控制

目录 1、流量控制 2、TCP 的拥塞控制 &#xff08;1&#xff09;拥塞控制的原理 &#xff08;2&#xff09;拥塞控制的具体方法 1、流量控制 一般说来&#xff0c;我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快&#xff0c;接收方就可能来不及接收&#x…

java项目的构建工具-Maven

黑马程序员JavaWeb开发教程 文章目录 一、概述1、介绍&#xff08;1&#xff09;介绍&#xff08;2&#xff09;Maven的作用&#xff08;3&#xff09;官网&#xff08;4&#xff09;仓库 2、安装 二、IDEA 集成 Maven1、配置Maven环境2、创建Maven项目&#xff08;1&#xff0…

万字总结!Docker简介及底层关键技术剖析

本文首发在个人博客上&#xff1a;万字总结&#xff01;Docker简介及底层关键技术剖析 Docker 简介 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#x…