设计模式学习-使用go实现原型模式
原型模式
定义
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。
原型模式是能基于拷贝来的,对于拷贝我们知道有两种形式,深拷贝和浅拷贝
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
原型模式浅拷贝:
1、省内存,拷贝时间更快;
2、浅拷贝容易出现原始数据被修改的情况,一般不建议使用;
3、浅拷贝可以拷贝不可变对象;
原型模式深拷贝:
1、数据完全隔离;
2、不过数据量大的情况下,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间;
代码实现
// Cloneable 是原型对象需要实现的接口
type Cloneable interface {
Clone() Cloneable
}
type PrototypeManager struct {
prototypes map[string]Cloneable
}
func NewPrototypeManager() *PrototypeManager {
return &PrototypeManager{
prototypes: make(map[string]Cloneable),
}
}
func (p *PrototypeManager) Get(name string) Cloneable {
return p.prototypes[name].Clone()
}
func (p *PrototypeManager) Set(name string, prototype Cloneable) {
p.prototypes[name] = prototype
}
测试文件
var (
deepCopyManager *PrototypeManager
shallowCopyManager *PrototypeManager
)
// 深拷贝实现Cloneable
type DeepCopy struct {
name string
}
func (t *DeepCopy) Clone() Cloneable {
tc := *t
return &tc
}
// 浅拷贝实现Cloneable
type ShallowCopy struct {
name string
}
func (t *ShallowCopy) Clone() Cloneable {
return t
}
func TestDeepCopyClone(t *testing.T) {
t1 := deepCopyManager.Get("dc")
t2 := t1.Clone()
// 深拷贝,指向的不是同一个变量的地址
if t1 == t2 {
t.Fatal("error! get clone not working")
}
t21 := t2.(*DeepCopy)
t21.name = "ShallowCopy-test"
t11 := t1.(*DeepCopy)
// 深拷贝name,不会影响到copy前的变量
if t11.name == t21.name {
t.Fatal("shallowCopy err")
}
}
func TestShallowCopyClone(t *testing.T) {
t1 := shallowCopyManager.Get("sc")
t2 := t1.Clone()
// 浅拷贝,变量地址的指向不变
if t1 != t2 {
t.Fatal("error! get clone not working")
}
t21 := t2.(*ShallowCopy)
t21.name = "ShallowCopy-test"
t11 := t1.(*ShallowCopy)
// 深拷贝name,copy之前的变量和copy之后的变量同时更改
if t11.name != t21.name {
t.Fatal("shallowCopy err")
}
}
func init() {
deepCopyManager = NewPrototypeManager()
dc := &DeepCopy{
name: "deepCopy",
}
deepCopyManager.Set("dc", dc)
shallowCopyManager = NewPrototypeManager()
sc := &ShallowCopy{
name: "shallowCopy",
}
shallowCopyManager.Set("sc", sc)
}
优点
1、使用原型模式创建对象比直接new一个对象在性能上要好的多,因为是直接进行的内存拷贝,比初始化性能上会好很多;
2、简化对象的创建,对于创建对象就像我们在编辑文档时的复制粘贴一样简单。
缺点
克隆包含循环引用的复杂对象可能会非常麻烦。
适用场景
1、在项目中,如果存在大量相同或相似对象的创建,如果用传统的构造函数来创建对象,会比较复杂和耗费资源,用原型模式生产对象就很高效;
2、对象创建过程比较麻烦,但复制比较简单的时候;
参考
【文中代码】https://github.com/boilingfrog/design-pattern-learning/tree/master/原型模式
【大话设计模式】https://book.douban.com/subject/2334288/
【极客时间】https://time.geekbang.org/column/intro/100039001
【原型模式】https://github.com/senghoo/golang-design-pattern
【原文地址】https://boilingfrog.github.io/2021/11/08/使用go实现原型模式/
设计模式学习-使用go实现原型模式的更多相关文章
- C#设计模式学习笔记:(5)原型模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,记录一下学习过程以备后续查用. 一.引言 很多人说原型设计模式会节省机器内存,他们说 ...
- 设计模式之第9章-原型模式(Java实现)
设计模式之第9章-原型模式(Java实现) “快到春节了,终于快放假了,天天上班好累的说.”“确实啊,最近加班比较严重,项目快到交付了啊.”“话说一到过节,就收到铺天盖地的短信轰炸,你说发短信就发吧, ...
- .NET设计模式(6):原型模式(Prototype Pattern)(转)
概述 在软件系统中,有时候面临的产品类是动态变化的,而且这个产品类具有一定的等级结构.这时如果用工厂模式,则与产品类等级结构平行的工厂方法类也要随着这种变化而变化,显然不大合适.那么如何封装这种动态的 ...
- .NET设计模式(6):原型模式(Prototype Pattern)
):原型模式(Prototype Pattern) ); //使用颜色 string colorName = "red"; C ...
- 设计模式总结篇系列:原型模式(Prototype)
首先对原型模式进行一个简单概念说明:通过一个已经存在的对象,复制出更多的具有与此对象具有相同类型的新的对象. 在理解Java原型模式之前,首先需要理解Java中的一个概念:复制/克隆. 在博文< ...
- Java 设计模式系列(五)原型模式
Java 设计模式系列(五)原型模式 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是选型模式的用意. 一.原型模 ...
- Java设计模式学习笔记(二) 简单工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...
- Java设计模式学习笔记(三) 工厂方法模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
随机推荐
- Jmeter系列(3) - 静默压测
前言 Windows环境 简述 静默 : 脱离UI运⾏JMeter压测,用命令行方式运行性能测试脚本好处:命令运⾏更容易"搞事情"命令格式: jmeter –n –t $jmx_f ...
- JS获取contextPath的方法
function getContextPath() { var pathName = document.location.pathname; var index = pathName.subst ...
- feign的一个注解居然隐藏这么多知识!
引言 最近由于业务的需要,需要接入下阿里云的一个接口,打开文档看了看这个接口看下来还是比简单的目测个把小时就可以搞定,但是接入的过程还是比较坎坷的.首先我看了看他给的示例,首先把阿里云文档推荐的dem ...
- electron-builder进行DEBUG输出的正确方式
前言 使用Electron进行打包通常会用到electron-builder或者electron-packager两种工具.在使用electron-builder的时候,由于对机制的不熟悉,我们在打包 ...
- postgresql高可用集群部署
一.概况 1.概念 pgsql高可用集群采用postgresql+etcd+patroni+haproxy+keepalived等软件实现,以postgresql做数据库,etcd存储集群状态,pat ...
- appium启动ios系统上面的app需求的参数
Appium启动APP至少需要7个参数 'platformVersion','deviceName'.'udid'.'bundleId'.'platformName'.'automationName ...
- 02Prism WPF 入门实战 - 建项
1.概要 Prism介绍 Github: https://github.com/PrismLibrary/Prism 开发文档:https://prismlibrary.com/docs/ Prism ...
- 消息队列那么多,为什么建议深入了解下RabbitMQ?
你为啥要在项目中选择xxx消息中间件? 提起消息队列,也许你的脑海里会不自觉地蹦出好多概念:JMS.Kafka.RocketMQ.AMQP.RabbitMQ.ActiveMQ.Pulsar.Redis ...
- Java中的函数式编程(三)lambda表达式
写在前面 lambda表达式是一个匿名函数.在Java 8中,它和函数式接口一起,共同构建了函数式编程的框架. lambda表达式乍看像是匿名内部类的一种语法糖,但实际上,它们是两种本质不同的事物 ...
- JAVA复习总体大纲
1 java基础. [1].变量--- 数据类型 变量名=值; 数据类型: 1.基本数据类型. byte[1字节] short[2字节] int[4字节] long[8字节] float[4字节] d ...