Go和Java实现原型模式

Go和Java实现原型模式

下面将通过一个克隆的示例来说明原型模式的使用。

1、原型模式

原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对

象的最佳方式之一。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种

模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它

的克隆,在需要的时候更新数据库,以此来减少数据库调用。

  • 意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

  • 主要解决:在运行期建立和删除原型。

  • 何时使用:1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定

    时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只

    能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类

    更方便一些。

  • 如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

  • 关键代码:1、实现克隆操作,在 JAVA 实现 Cloneable 接口,重写 clone(),在 .NET 中可以使用 Object 类的

    MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔

    离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

  • 应用实例:1、细胞分裂。 2、JAVA 中的 Object clone() 方法。

  • 优点:1、性能提高。 2、逃避构造函数的约束。

  • 缺点:1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很

    容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable

    接口。

  • 使用场景:1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、

    性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型

    模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要

    修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出

    现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型

    模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

  • 注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象

    的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

  • 适用性:

    当一个系统应该独立于它的产品创建、构成和表示时。

    当要实例化的类是在运行时刻指定时,例如通过动态装载。

    为了避免创建一个与产品类层次平行的工厂层次时。

    当一个类的实例只能有几个不同状态组合中的一种时。

    建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

2、Go实现原型模式

package prototype// ========== Cloneable ==========
// Cloneable是原型对象需要实现的接口
type Cloneable interface {Clone() Cloneable
}
package prototypeimport "encoding/json"// ========== DeepCopy ==========
// 深拷贝实现Cloneable
type DeepCopy struct {Name string
}// clone也可以使用序列化与反序列化的方式实现深拷贝
func (t *DeepCopy) SerializableClone() Cloneable {var cloneable Cloneableb, _ := json.Marshal(t)json.Unmarshal(b, &cloneable)return cloneable
}func (t *DeepCopy) Clone() Cloneable {tc := *treturn &tc
}
package prototype// ========== ShallowCopy ==========
// 浅拷贝实现Cloneable
type ShallowCopy struct {Name string
}func (t *ShallowCopy) Clone() Cloneable {return t
}
package prototype// ========== PrototypeManager ==========
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
}
package mainimport ("fmt". "proj/prototype"
)var (deepCopyManager    *PrototypeManagershallowCopyManager *PrototypeManager
)func init() {deepCopyManager = NewPrototypeManager()deepCopyManager.Set("dc", &DeepCopy{Name: "DeepCopy"})shallowCopyManager = NewPrototypeManager()shallowCopyManager.Set("sc", &ShallowCopy{Name: "ShallowCopy"})
}func main() {// ========== TestDeepCopyClone ==========t1 := deepCopyManager.Get("dc")t2 := t1.Clone()// 深拷贝,指向的不是同一个变量的地址// falsefmt.Println(t1 == t2)t3 := t2.(*DeepCopy)t3.Name = "DeepCopyUpdate"t4 := t1.(*DeepCopy)// 深拷贝Name,不会影响到copy前的变量// DeepCopyUpdatefmt.Println(t3.Name)// DeepCopyfmt.Println(t4.Name)// ========== TestShallowCopyClone ==========t5 := shallowCopyManager.Get("sc")t6 := t5.Clone()// 浅拷贝,变量地址的指向不变// truefmt.Println(t5 == t6)t7 := t6.(*ShallowCopy)t7.Name = "ShallowCopyUpdate"t8 := t5.(*ShallowCopy)// 浅拷贝Name,copy之前的变量和copy之后的变量同时更改// ShallowCopyUpdatefmt.Println(t7.Name)// ShallowCopyUpdatefmt.Println(t8.Name)
}

3、Java实现原型模式

创建一个抽象类 Shape 和扩展了 Shape 类的实体类,然后定义类 ShapeCache,该类把 shape 对象存储在一个

Hashtable 中,并在请求的时候返回它们的克隆。

package com.prototype;// ========== Shape ==========
public abstract class Shape implements Cloneable {private String id;protected String type;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getType() {return type;}public void setType(String type) {this.type = type;}abstract void draw();@Overridepublic Object clone() {Object clone = null;try {clone = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}
}
package com.prototype;// ========== Circle ==========
public class Circle extends Shape {public Circle(){type = "Circle";}@Overridepublic void draw() {System.out.println("Draw Circle!");}
}
package com.prototype;// ========== Rectangle ==========
public class Rectangle extends Shape {public Rectangle(){type = "Rectangle";}@Overridepublic void draw() {System.out.println("Draw Rectangle!");}
}
package com.prototype;// ========== Square ==========
public class Square extends Shape {public Square(){type = "Square";}@Overridepublic void draw() {System.out.println("Draw Square!");}
}
package com.prototype;import java.util.Hashtable;// ========== ShapeCache ==========
public class ShapeCache {private final static Hashtable<String, Shape> SHAPE_MAP = new Hashtable<>();public static Shape getShape(String shapeId) {Shape cachedShape = SHAPE_MAP.get(shapeId);// 这里是浅拷贝,返回一个新的对象// 新对象里的引用类型变量地址指向的还是原对象内引用类型地址return (Shape) cachedShape.clone();}// 对每种形状都运行数据库查询,并创建该形状public static void loadCache() {Circle circle = new Circle();circle.setId("1");SHAPE_MAP.put(circle.getId(),circle);Square square = new Square();square.setId("2");SHAPE_MAP.put(square.getId(),square);Rectangle rectangle = new Rectangle();rectangle.setId("3");SHAPE_MAP.put(rectangle.getId(),rectangle);}
}
package com.prototype;public class Test {public static void main(String[] args) {ShapeCache.loadCache();Shape clonedShape = ShapeCache.getShape("1");System.out.println("Shape : " + clonedShape.getType());clonedShape.draw();Shape clonedShape2 = ShapeCache.getShape("2");System.out.println("Shape : " + clonedShape2.getType());clonedShape.draw();Shape clonedShape3 = ShapeCache.getShape("3");System.out.println("Shape : " + clonedShape3.getType());clonedShape3.draw();}
}
# 输出
Shape : Circle
Draw Circle!
Shape : Square
Draw Circle!
Shape : Rectangle
Draw Rectangle!

4、深拷贝和浅拷贝的区别

深拷贝和浅拷贝是指在复制一个对象时,复制的方式不同。

在进行深拷贝时,复制的是对象及其内部的所有对象。这意味着,如果原始对象中包含一个列表,那么在深拷贝

后,原始对象和拷贝对象中的列表是两个独立的对象,即使它们看起来完全相同,也不会相互影响。

相反,浅拷贝仅复制对象本身,但是如果对象内部包含其他对象,则这些对象并不会被复制。因此,如果原始对象

中包含一个列表,那么在浅拷贝后,原始对象和拷贝对象中的列表是同一个对象。如果你在拷贝对象中更改了列

表,那么原始对象中的列表也会发生变化。

总:

复制对象后,如果修改了原对象或新对象的数据,造成了对其他对象的数据也同时发生了变化的现象,就是浅拷

贝,对象之间仍然存在关联。

如果复制后的对象与原对象,无论数据如何变化,都不会对其它对象带来变化,就是深拷贝,对象之间已经毫无关

系。

5、补充Java的深拷贝和浅拷贝的实现

5.1 浅拷贝

package com.shallowcopy;// ========== ShallowCopyDemo ==========
public class ShallowCopyDemo {public static void main(String[] args) {// ======浅拷贝=============System.out.println("======浅拷贝=============");// 初始化对象User user = new User();user.setAge(25);Name name = new Name();name.setFirst("li");name.setSecond("si");user.setName(name);// 实现对象克隆User cloneUser = (User) user.clone();// 修改原始对象属性值cloneUser.setAge(27);cloneUser.getName().setFirst("wang");cloneUser.getName().setSecond("wu");// 源对象:User{age=25, name=Name{first='wang', second='wu'}}System.out.println("源对象:" + user);// 新对象:User{age=27, name=Name{first='wang', second='wu'}}System.out.println("新对象:" + cloneUser);// 在clone()方法中,我们仅对User对象实现了克隆,但是没有对User类下的属性类Name进行克隆// 执行克隆后,新User对象下的Name属性与原对象下的Name属性,仍然指向同一块内存// 如果Name属性发生变更,所有克隆对象的Name属性都会变化,此即为浅克隆}
}class User implements Cloneable{int age;Name name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Name getName() {return name;}public void setName(Name name) {this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name=" + name +'}';}// 实现Cloneable接口并重写Object类的clone()方法@Overridepublic Object clone() {try {return super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}
}class Name{String first;String second;public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getSecond() {return second;}public void setSecond(String second) {this.second = second;}@Overridepublic String toString() {return "Name{" +"first='" + first + '\'' +", second='" + second + '\'' +'}';}
}

5.2 深拷贝

package com.deepcopy;// ========== DeepCopyDemo ==========
public class DeepCopyDemo {public static void main(String[] args) {// ======深拷贝=============System.out.println("======深拷贝=============");// 初始化对象User user = new User();user.setAge(25);Name name = new Name();name.setFirst("li");name.setSecond("si");user.setName(name);// 实现对象克隆User cloneUser = (User) user.clone();// 修改原始对象属性值cloneUser.setAge(27);cloneUser.getName().setFirst("wang");cloneUser.getName().setSecond("wu");// 源对象:User{age=25, name=Name{first='li', second='si'}}System.out.println("源对象:" + user);// 新对象:User{age=27, name=Name{first='wang', second='wu'}}System.out.println("新对象:" + cloneUser);}
}class Name implements Cloneable{String first;String second;public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getSecond() {return second;}public void setSecond(String second) {this.second = second;}@Overridepublic String toString() {return "Name{" +"first='" + first + '\'' +", second='" + second + '\'' +'}';}// 实现Cloneable接口并重写Object类的clone()方法@Overridepublic Object clone() {try {return super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}
}class User implements Cloneable{int age;Name name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Name getName() {return name;}public void setName(Name name) {this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name=" + name +'}';}// 实现Cloneable接口并重写Object类的clone()方法// 这种方法实现的深克隆比较笨重,如果User类下有多个属性类时,要实现深克隆就需要对所有类重写clone()方法@Overridepublic Object clone() {try {User u = (User) super.clone();//调用属性的克隆方法u.setName((Name) this.name.clone());return u;} catch (CloneNotSupportedException e) {e.printStackTrace();}return null;}
}

5.3 fastjson实现深拷贝

package com.fastjsondeepcopy;import com.alibaba.fastjson.JSON;public class FastjsonDemo {public static void main(String[] args) {// ======深拷贝=============System.out.println("======深拷贝=============");// 初始化对象User user = new User();user.setAge(25);Name name = new Name();name.setFirst("li");name.setSecond("si");user.setName(name);// 实现对象克隆String jsonString = JSON.toJSONString(user);User cloneUser = JSON.parseObject(jsonString, User.class);// 修改原始对象属性值cloneUser.setAge(27);cloneUser.getName().setFirst("wang");cloneUser.getName().setSecond("wu");// 源对象:User{age=25, name=Name{first='li', second='si'}}System.out.println("源对象:" + user);// 新对象:User{age=27, name=Name{first='wang', second='wu'}}System.out.println("新对象:" + cloneUser);}
}class User{int age;Name name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Name getName() {return name;}public void setName(Name name) {this.name = name;}@Overridepublic String toString() {return "User{" +"age=" + age +", name=" + name +'}';}
}class Name{String first;String second;public String getFirst() {return first;}public void setFirst(String first) {this.first = first;}public String getSecond() {return second;}public void setSecond(String second) {this.second = second;}@Overridepublic String toString() {return "Name{" +"first='" + first + '\'' +", second='" + second + '\'' +'}';}
}

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

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

相关文章

使用罗技鼠标后 弹出当前页面的脚本发生错误AppData/Local/Temp/LogiUI/Pak/js/jquery-1.3.2.min.js解决

使用的台式机&#xff0c;没有蓝牙驱动&#xff0c;在用logi无线鼠标时&#xff0c;把鼠标连接插入台式机后弹出的如上图所示这个提示&#xff0c;无论是点是/否&#xff0c;还是X掉上图提示&#xff0c;电脑右下角的图依然存在。不习惯这丫的存在。 我重启还是有&#xff0c;然…

Linux shell yes命令(不停输出换行的y)(不停输出换行的指定字符串)(脚本自动确认y)

文章目录 yes命令功能doc文档英文中文翻译完整文档 示例应用案例自动为脚本多次确认y yes命令功能 yes命令可以不断地输出换行的指定字符串&#xff0c;不加参数时&#xff0c;不断输出换行的“y”&#xff0c;有时我们需要执行一些需要用户键入“y”确认的脚本&#xff0c;但…

PoseiSwap 开启“Poseidon”池,治理体系或将全面开启

PoseiSwap曾在前不久分别以IDO、IEO的方式推出了POSE通证&#xff0c;但PoseiSwap DEX中并未向除Zepoch节点外的角色开放POSE资产的交易。而在前不久&#xff0c;PoseiSwap推出了全新的“Poseidon”池&#xff0c;该池将向所有用户开放&#xff0c;并允许用户自由的进行质押、交…

oracle基础语法和备份恢复

Oracle总结 sql命令分类 1.DDL&#xff0c;数据定义语言&#xff0c;create创建/drop销毁 2.DCL&#xff0c;数据库控制语言&#xff0c;grant授权/revoke撤销 3.DML&#xff0c;数据操纵语言&#xff0c;insert/update/delete等sql语句 4.DQL&#xff0c;数据查询语言&am…

HTML5 中新增了哪些表单元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTML5 中新增了的表单元素⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚…

笔记:Android 9系统启动流程

启动流程 1.按下电源&#xff0c;系统启动 当电源键按下时&#xff0c;引导芯片代码&#xff08;汇编指令&#xff09;会从预定的地方&#xff08;固化在ROM&#xff09;开始执行&#xff0c;将引导程序 BootLoader 加载到 RAM中&#xff0c;然后执行 2.引导程序 BootLoader …

微服务架构基础--第3章Spring Boot核心功能讲解

第3章Spring Boot核心功能讲解 一.预习笔记 1.使用maven创建SpringBoot项目 1-1:创建一个maven项目 1-2:在pom文件中导入依赖 1-3&#xff1a;编写启动类&#xff08;注意启动类的位置&#xff09; 1-4&#xff1a;编写测试类 1-5&#xff1a;运行SpringBoot启动类 2.了解p…

C语言案例 完全平方数-07

题目&#xff1a;一个整数&#xff0c;它加上100后是一个完全平方数&#xff0c;再加上168又是一个完全平方数&#xff0c;请问该数是多少&#xff1f; 步骤一&#xff1a;定义程序目标 编写C程序&#xff0c;计算一个整数&#xff0c;它加上100后是一个完全平方数&#xff0c…

android:clipToPadding=“false“的使用

当Recyclerview设置padding了&#xff0c;希望列表滚动时&#xff0c;内容可以渲染到顶部和底部的padding区域&#xff0c;可以使用设置 android:clipToPadding"false" <androidx.recyclerview.widget.RecyclerViewandroid:id"id/recycler_view"andro…

Android Studio 屏幕适配

Android开发屏幕适配流程 首先studio中没有ScreenMatch这个插件的&#xff0c;下去现在这个插件 点击File->settings->Plugins->(搜索ScreenMatch插件)&#xff0c;点击下载&#xff0c;应用重启Studio即可&#xff0c;如下图 在values下 创建dimens.xml&#xff0c…

自动优化图片

1.压缩jpeg&#xff1a; 接到这个任务&#xff0c;我首先找到了jpegoptim&#xff08;https://github.com/tjko/jpegoptim&#xff09;,然后编译&#xff0c;实验了一下&#xff1a; jpegoptim.exe -o input.jpg -S 90% -d dest_path 或 jpegoptim.exe -o input.jpg -m 90 -d…

升级node版本后vue2的项目node-sass、sass-loader安装报错(14.x升级到16.x)

node升级到16.x版本后&#xff0c;对应的node-sass需要升级到^6.0.0&#xff0c;此时sass-loader的版本需要升级到10.2.0以上 &#xff0c;具体对应版本规则可参考链接: https://github.com/webpack-contrib/sass-loader/releases?page3 vue2通过vue/cli创建的项目&#xff0…

学会RabbitMQ的延迟队列,提高消息处理效率

系列文章目录 手把手教你&#xff0c;本地RabbitMQ服务搭建&#xff08;windows&#xff09; 消息队列选型——为什么选择RabbitMQ RabbitMQ灵活运用&#xff0c;怎么理解五种消息模型 RabbitMQ 能保证消息可靠性吗 推或拉&#xff1f; RabbitMQ 消费模式该如何选择 死信是什么…

C++初阶——函数重载

前言&#xff1a;C中除了可以在不同的命名空间中使用同名函数&#xff0c;还有一种支持在同一个作用域中同名函数的方式——函数重载。 函数重载 一.什么是函数重载&#xff1f;二.函数重载的3种规则三.特殊情况 一.什么是函数重载&#xff1f; C允许同样同一作用域中声明几个功…

Ubuntu 20.04 安装 Stable Diffusionn

步骤 1&#xff1a;安装 wget、git、Python3 和 Python3虚拟环境&#xff08;如果已安装可忽略这步骤&#xff09; sudo apt install wget git python3 python3-venv步骤 2&#xff1a;克隆 SD 项目到本地 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webu…

Vscode python调试和运行环境设置

Vscode python调试和运行环境设置 文章目录 Vscode python调试和运行环境设置前言一、是否为每次运行python程序都要选择环境烦恼二、是否为python程序调试不能进标准/第三方库而烦恼 前言 一、是否为每次运行python程序都要选择环境烦恼 在.vscode文件夹(没有就自己造一个)下…

Flink之SideOutput(数据分流)

Flink在早期版本有一个split算子用来做数据分流使用的,但是在flink-1.12开始这个API就已经被删除了,在1.12版本以后我们是通过process算子来做数据分流的,这里就介绍一下如何使用prodess进行数据分流. 代码 import org.apache.flink.api.common.typeinfo.TypeInformation; im…

【网络编程】实现一个简单多线程版本TCP服务器(附源码)

TCP多线程 &#x1f335;预备知识&#x1f384; Accept函数&#x1f332;字节序转换函数&#x1f333;listen函数 &#x1f334;代码&#x1f331;Log.hpp&#x1f33f;Makefile☘️TCPClient.cc&#x1f340;TCPServer.cc&#x1f38d; util.hpp &#x1f335;预备知识 &…

RabbitMQ - 简单案例

目录 0.引用 1.Hello world 2.轮训分发消息 2.1 抽取工具类 2.2 启动两个工作线程接受消息 2.4 结果展示 3.消息应答 3.1 自动应答 3.2 手动消息应答的方法 3.3 消息自动重新入队 3.4 消息手动应答代码 4.RabbitMQ 持久化 4.1 队列如何实现持久化 4.2 消息实现持久化 5.不…

对 Promise 的理解

Promise 是异步编程的一种解决方案&#xff0c;它是一个对象&#xff0c;可以获取异步 操作的消息&#xff0c;他的出现大大改善了异步编程的困境&#xff0c;避免了地狱回调&#xff0c; 它比传统的解决方案回调函数和事件更合理和更强大。 所谓 Promise&#xff0c;简单说就…