前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【设计模式自习室】原型模式

【设计模式自习室】原型模式

作者头像
蛮三刀酱
发布于 2019-12-30 10:00:08
发布于 2019-12-30 10:00:08
43700
代码可运行
举报
运行总次数:0
代码可运行

前言

《设计模式自习室》系列,顾名思义,本系列文章带你温习常见的设计模式。主要内容有:

  • 该设计模式的详细介绍,包括:
    • 引子,意图(大白话解释)
    • 类图,时序图(理论规范)
  • 该模式的代码示例:熟悉该模式的代码长什么样子
  • 该模式的优缺点:不可以滥用模式
  • 该模式的实际使用案例:了解它在哪些重要的源码中出现过

该系列会逐步更新于我的博客和公众号(博客见文章底部)

也希望各位观众老爷能够关注我的个人公众号:后端技术漫谈,不会错过精彩好看的文章。

系列文章回顾

原型模式 Prototype

引子

还记得深克隆和浅克隆的区别吗?其实这里说的克隆,就是原型模式。

原型模式要求对象实现一个可以克隆自身的接口(类型)。这样一来,通过原型实例创建新的对象。

原型模式也属于创建型模式。

意图

原型模式有两种表现形式:

  • 简单形式
  • 登记形式

他们的区别在于:第二种登记模式中,多了一个原型管理器(PrototypeManager)角色,该角色的作用是:创建具体原型类的对象,并记录每一个被创建的对象。

如果需要创建的原型对象数目较少而且比较固定的话,可以采取简单形式。在这种情况下,原型对象的引用可以由客户端自己保存。

否则,你可以使用登记形式。原型管理器的作用:

在登记形式下,客户端不保存对原型对象的引用,这个任务被交给原型管理器角色。在克隆一个对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象。如果有,可以从原型管理器角色中取得这个对象引用;如果没有,客户端就需要自行复制此原型对象。

类图

简单形式
  • 客户(Client):客户类提出创建对象的请求;
  • 抽象原型(Prototype):这是一个抽象角色,通常是一个Java接口或者抽象类。此角色定义了的具体原型类所需的实现的方法。
  • 具体原型(Concrete Prototype):此角色需要实现抽象原型角色要求的克隆相关的接口。
登记形式

多出了:

  • 原型管理器(PrototypeManager):客户端client直接调用原型管理器

时序图

使用举例和实际使用场景举例

本文将使用举例和实际使用场景举例放在一起来讨论,是由于原型模式最典型的例子就是Java的深克隆和浅克隆 (clone方法),我们直接使用深克隆和浅克隆的代码来熟悉原型模式。

clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的。一般而言,clone()方法满足以下的描述:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1)对任何的对象x,都有:x.clone()!=x。换言之,克隆对象与原对象不是同一个对象。
(2)对任何的对象x,都有:x.clone().getClass() == x.getClass(),换言之,克隆对象与原对象的类型一样。
(3)如果对象x的equals()方法定义其恰当的话,那么x.clone().equals(x)应当成立的。

在JAVA语言的API中,凡是提供了clone()方法的类,都满足上面的这些条件。JAVA语言的设计师在设计自己的clone()方法时,也应当遵守着三个条件。一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的。

浅复制 clone()

当进浅复制时,clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。同时,复制出来的对象具有与原对象一致的状态。

此处对象一致的状态是指:复制出的对象与原对象中的属性值完全相等==。

代码示例:

我们复制一本书

1.定义Book类和Author类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Author {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Book implements Cloneable {

    private String title;
    private int pageNum;
    private Author author;

    public Book clone() {
        Book book = null;
        try {
            book = (Book) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return book;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

}

2.测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.qqyumidi;

public class PrototypeTest {

    public static void main(String[] args) {
        Book book1 = new Book();
        Author author = new Author();
        author.setName("corn");
        author.setAge(100);
        book1.setAuthor(author);
        book1.setTitle("好记性不如烂博客");
        book1.setPageNum(230);

        Book book2 = book1.clone();
        
        System.out.println(book1 == book2);  // false
        System.out.println(book1.getPageNum() == book2.getPageNum());   // true
        System.out.println(book1.getTitle() == book2.getTitle());        // true
        System.out.println(book1.getAuthor() == book2.getAuthor());        // true
        
    }
}

虽然复制出来的对象重新在堆上开辟了内存空间,但是,对象中各属性确保持相等。对于基本数据类型很好理解,但对于引用数据类型来说,则意味着此引用类型的属性所指向的对象本身是相同的, 并没有重新开辟内存空间存储。换句话说,引用类型的属性所指向的对象并没有复制。

由此,我们将其称之为浅复制。

而当复制后的对象的引用类型的属性所指向的对象也重新得以复制,此时,称之为深复制。

深复制 deepclone()

Java中的深复制一般是通过对象的序列化和反序列化得以实现。序列化时,需要实现Serializable接口。

从输出结果中可以看出,深复制不仅在堆内存上开辟了空间以存储复制出的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。

深复制的两种实现方式

在Java语音中,想要实现深度拷贝其实有两种方式:

  • 通过序列化
  • 重写clone,调用子成员的clone方法

代码示例:通过 序列化 实现深复制

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public  Object deepClone() throws IOException, ClassNotFoundException{
        //将对象写到流里
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //从流里读回来
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }

代码示例:通过 重写clone 实现深复制

1.定义Book类和Author类(注意:不仅Book类需要实现Serializable接口,Author同样也需要实现Serializable接口!!):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Author implements Serializable{

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Book implements Serializable {

    private String title;
    private int pageNum;
    private Author author;

    public Book deepClone() throws IOException, ClassNotFoundException{
        // 写入当前对象的二进制流 
        ByteArrayOutputStream bos = new ByteArrayOutputStream();  
        ObjectOutputStream oos = new ObjectOutputStream(bos);  
        oos.writeObject(this);
        
        // 读出二进制流产生的新对象  
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
        ObjectInputStream ois = new ObjectInputStream(bis);  
        return (Book) ois.readObject();
    }
    
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

}

2.测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class PrototypeTest {

    public static void main(String[] args) throws ClassNotFoundException, IOException {
        Book book1 = new Book();
        Author author = new Author();
        author.setName("corn");
        author.setAge(100);
        book1.setAuthor(author);
        book1.setTitle("好记性不如烂博客");
        book1.setPageNum(230);

        Book book2 = book1.deepClone();
        
        System.out.println(book1 == book2);  // false
        System.out.println(book1.getPageNum() == book2.getPageNum());   // true
        System.out.println(book1.getTitle() == book2.getTitle());        // false
        System.out.println(book1.getAuthor() == book2.getAuthor());        // false
        
    }
}

深复制不仅在堆内存上开辟了空间以存储复制出的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。

该模式的优缺点

优点

原型模式允许在运行时动态改变具体的实现类型。原型模式可以在运行期间,有客户来注册符合原型接口的实现类型,也可以动态的改变具体的实现类型,看起来接口没有任何变化,但是其实运行的已经是另外一个类实体了。因为克隆一个原型对象就类似于实例化一个类。

缺点

缺点就是…你需要自己写一个clone方法

参考

https://juejin.im/post/5b48bec15188251b3d79bf9c

https://www.cnblogs.com/java-my-life/archive/2012/04/11/2439387.html

https://www.jianshu.com/p/b0e13717b6d9

《Head First设计模式》

关注我

我是一名后端开发工程师。

主要关注后端开发,数据安全,爬虫,物联网边缘计算等方向,欢迎交流。

各大平台都可以找到我

原创博客主要内容

  • Java面试知识点复习全手册
  • 设计模式/数据结构 自习室
  • Leetcode/剑指offer 算法题解析
  • SpringBoot/SpringCloud菜鸟入门实战系列
  • 爬虫相关技术文章
  • 后端开发相关技术文章
  • 逸闻趣事/好书分享/个人兴趣

个人公众号:后端技术漫谈

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
单细胞RNA-seq数据分析最佳实践(上)
Luecken MD, Theis FJ. Current best practices in single-cell RNA-seq analysis: a tutorial. Mol. Syst. Biol. 2019, 15: e8746.
生信技能树jimmy
2020/03/30
2.6K0
21天精通单细胞数据分析Day02:理解条码
当序列与参考基因组进行比对时,我们便可以看到它与哪个基因位点对齐,并据此定性地断言,结合上述两条信息,该序列描绘了来自特定细胞的特定基因的转录本。
简说基因
2024/06/12
1190
21天精通单细胞数据分析Day02:理解条码
单细胞专题 | 2.如何开始单细胞RNASeq数据分析
在我们分析之前,最好是先阅读一下相关的文献综述。对于单细胞数据的分析,我找了几篇相关的文献综述。
DoubleHelix
2022/06/13
1.8K0
单细胞专题 | 2.如何开始单细胞RNASeq数据分析
XYZeq:一种空间可辨的单细胞RNA测序揭示了肿瘤微环境中的表达异质性
在过去的十年里,组织单细胞RNA测序技术(scRNA-seq)已经成为了用于分析组织细胞异质性的一种强有力工具,虽然借助于scRNA-seq可以了解组织样本中的细胞类型和异质性差异,但不能够提供细胞空间组织的信息。本文开发了XYZeq技术,该技术可将单细胞测序数据和细胞空间位置更好的整合在一起。
生信交流平台
2022/09/21
7020
XYZeq:一种空间可辨的单细胞RNA测序揭示了肿瘤微环境中的表达异质性
一文读懂scRNA-seq数据分析(建议收藏)
当我们进行单细胞数据分析时,应该始终从质量控制步骤开始,首先清理数据,以确保数据足以回答研究的问题。在此步骤之后,通常会继续进行定位(比对)或基因组组装步骤,具体取决于是否有参考基因组可供使用。
简说基因
2024/03/22
1.3K0
一文读懂scRNA-seq数据分析(建议收藏)
单细胞测序—基础分析流程
参考官方文档:https://satijalab.org/seurat/articles/pbmc3k_tutorial
sheldor没耳朵
2024/07/30
8270
单细胞测序—基础分析流程
【Science】万字综述:空间组学将去何方
空间组学被广泛宣称为生命科学的新前沿。这个术语涵盖了一系列技术,承诺将改变生物学的许多领域,并通过同时测量物理组织结构和分子特性,有望彻底革新病理学。尽管这个领域在过去5年已经成熟,但它仍然面临一些成长中的困扰:进入的门槛、稳定性、实验设计和分析的最佳实践不明确,以及缺乏标准化。在这篇综述中,我们系统地列举了空间组学技术的各种类型;强调了它们的原理、优势和局限性;并对这个极具潜力但仍难以驾驭的领域未来面临的最大挑战提出了一些观点和建议。
Chris生命科学小站
2023/08/29
1.5K0
【Science】万字综述:空间组学将去何方
热点综述 | 高维单细胞RNA测序数据分析工具
scRNA-seq数据集通常包含由于不完全RNA捕获、PCR扩增偏差和/或特定于患者或样本的批次效应而产生的技术噪声,如何降低技术噪声对数据分析的影响?
尐尐呅
2022/04/01
8520
热点综述 | 高维单细胞RNA测序数据分析工具
单细胞核测序在人类肾脏上的应用
当你的才华还撑不起你的野心时,请潜下心来,脚踏实地,跟着我们慢慢进步。不知不觉在单细胞转录组领域做知识分析也快两年了,通过文献速递这个栏目很幸运聚集了一些小伙伴携手共进,一起成长。
生信技能树jimmy
2020/03/30
7140
单细胞测序原理
单细胞测序主要包括以下四个步骤。其中非常关键的一点就是如何进行单细胞的捕获/分选,这是决定单细胞检测成本和通量的关键步骤。
生信喵实验柴
2022/10/25
1.6K0
单细胞测序原理
高维单细胞转录组数据处理最新(2020年3月)综述(万字长文)
看到隔壁《单细胞天地》公众号翻译了一个最新的单细胞数据处理综述,很精彩,所以申请转载到生信技能树平台以飨读者:
生信技能树
2020/05/14
2.7K0
高维单细胞转录组数据处理最新(2020年3月)综述(万字长文)
单细胞系列教程:计数矩阵是如何生成的?(二)
根据所使用的文库制备方法,RNA 序列(也称为读数或标签)将来自转录本(10X Genomics、CEL-seq2、Drop-seq)的 3' 末端(或 5' 末端) , inDrops) 或来自全长转录本 (Smart-seq)。
数据科学工厂
2023/01/25
8260
单细胞转录组数据分析必读综述
摸索单细胞转录组数据分析这两年,我遇到过太多的CNS文章及综述,但只有本文被我安排给了所有人进行翻译,本译文来自于最优秀的学习者,最开始在不到3000粉丝的单细胞天地公众号发布,却喜获近5000的阅读量。
生信技能树
2019/05/20
6.7K0
单细胞转录组数据分析必读综述
提供超全面代码,看看顶刊 Nat Med 是如何用单细胞和空间转录组研究癌症的
生信菜鸟团
2024/11/28
1280
提供超全面代码,看看顶刊 Nat Med 是如何用单细胞和空间转录组研究癌症的
综述:高维单细胞RNA测序数据分析工具(上)
当你的才华还撑不起你的野心时,请潜下心来,脚踏实地,跟着我们慢慢进步。不知不觉在单细胞转录组领域做知识分析也快两年了,通过文献速递这个栏目很幸运聚集了一些小伙伴携手共进,一起成长。
生信技能树jimmy
2020/05/19
2.2K0
关于什么是单细胞测序的知识整理,ChatGPT会做的更好吗?
既然ChatGPT如此擅长查询和整理资料,那么关于什么是单细胞测序的知识整理,ChatGPT会做的更好吗?我先给出来一个学徒的知识整理,借花献佛给大家。然后大家可以自己玩一下ChatGPT,看看能不能做出来如此出色的整理。
生信技能树
2023/02/27
9090
关于什么是单细胞测序的知识整理,ChatGPT会做的更好吗?
如何用单细胞研究癌症起源的单克隆与多克隆问题,提供详细原始代码
生信菜鸟团
2024/12/20
2000
如何用单细胞研究癌症起源的单克隆与多克隆问题,提供详细原始代码
单细胞RNA测序综述汇总—肿瘤研究的新工具
各种形式的肿瘤内异质性和复杂性会影响抗肿瘤治疗的疗效,导致治疗耐药性和转移。而近年来兴起的单细胞测序技术,结合数据整合方法的创新,使得精细理解肿瘤及肿瘤微环境中细胞间的相互作用,表征疾病进展过程中肿瘤内部结构成为可能,本文着重介绍单细胞RNAseq测序技术原理、肿瘤研究中应用、多组学数据整合分析、单细胞RNA测序未来发展等内容。
生信技能树jimmy
2020/03/27
1.8K0
单细胞转录组基本概念(一)
普通转录组的思路也可以应用到单细胞转录组。普通转录组相当于把一群细胞或一个器官混合到一起去提取RNA,获得的是每个细胞中RNA表达量的平均值。单细胞是把每个细胞单独分出来去提取RNA,然后建库测序,获得是是单个细胞的表达值。在每个细胞里面基因的表达具有随机性,且存在异质性。而且这些细胞群中会存在不同类型的细胞,尤其是当我们对整个组织或者器官进行测序时,它们本身就是由不同类型的细胞组成的,而我们用普通转录组来测序,相当于掩盖住了这些不同的细胞类型的差异,展示的是整个组织的平均的状态,所以说单细胞从这个来看跟普通转录组就不同在是用一个细胞测,不是用一堆细胞测。
生信宝典
2021/05/27
2.1K0
单细胞时代 || NGS技术实现
Single-Cell RNA Sequencing and Its Combination with Protein and DNA Analyses
生信技能树jimmy
2021/03/10
1.7K0
单细胞时代 || NGS技术实现
推荐阅读
相关推荐
单细胞RNA-seq数据分析最佳实践(上)
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 前言
    • 系列文章回顾
  • 原型模式 Prototype
    • 引子
    • 意图
    • 类图
    • 时序图
    • 使用举例和实际使用场景举例
    • 该模式的优缺点
    • 参考
  • 关注我
    • 各大平台都可以找到我
    • 原创博客主要内容
    • 个人公众号:后端技术漫谈
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档