设计模式之原型模式
创始人
2024-02-24 10:26:29
0

文章目录

  • 1.前言
    • 概念
    • 使用场景
  • 2.原型模式核心组成
    • UML图
  • 3.浅拷贝与深拷贝
    • 基本类型与引用类型
    • 浅拷贝
      • 代码演示
    • 深拷贝
      • 代码演示
  • 4.原型模式的优点与缺点

1.前言

概念

原型模式(Prototype Pattern)是用于创建重复的对象同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。工作原理是将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。

使用原型模式非常简单,实现一个接口,重写一个方法即完成了原型模式。

使用场景

  • 创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得
  • 如果系统要保存对象的状态,做备份使用

2.原型模式核心组成

  • Prototype: 声明克隆方法的接口,是所有具体原型类的公共父类,Cloneable接口
  • ConcretePrototype : 具体原型类
  • Client: 让一个原型对象克隆自身从而创建一个新的对象

UML图

请添加图片描述

因为克隆比较常用,所以Java提供了Cloneable接口,所以我们并不需要去编写Prototype接口,只需要实现Cloneable接口即可。不过Cloneable实现的是浅拷贝,如果想实现深拷贝,我们可以使用Serializable 接口。下面我们会细说分别使用浅拷贝与深拷贝实现原型模式。

3.浅拷贝与深拷贝

基本类型与引用类型

在Java中,基本类型有整数类型(long、int、short、byte),浮点类型(float、double),字符类型(char),布尔类型(boolean)。

除此之外所有的类型都是引用类型

从存储来说,基本类型与引用类型的区别在于:

  • 在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中的
  • 引用数据类型变量,栈中存放的是其具体内容所在内存的地址,而其具体内容都是存放在堆中的

浅拷贝

在浅拷贝中:

  • 如果原型对象的成员变量是基本数据类型,将复制一份给克隆对象;
  • 如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象, 也就是说原型对象和克隆对象的成员变量指向相同的内存地址

代码演示

接下来我们使用Resume类来讲解。

具体原型类

package ProtoType.ShallowCopy;import java.util.List;/*** @Author: 少不入川* @Date: 2022/11/28 21:19*/
public class Resume implements Cloneable{private String name;private int age;private List technologyStack;public Resume(){}public Resume(String name, int age, List technologyStack){this.name = name;this.age = age;this.technologyStack = technologyStack;}public List getTechnologyStack() {return technologyStack;}public void setTechnologyStack(List technologyStack) {this.technologyStack = technologyStack;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Resume{" +"name='" + name + '\'' +", age=" + age +", technologyStack=" + technologyStack +'}';}// 使用public修饰符方便调用@Overridepublic Object clone(){Resume resume = null;try{resume = (Resume) super.clone();}catch (Exception e){e.printStackTrace();}return resume;}
}

测试类

package ProtoType.ShallowCopy;import java.util.ArrayList;/*** @Author: 少不入川* @Date: 2022/11/28 21:58*/
public class ShallowCopyTest {public static void main(String[] args) {Resume resume1 = new Resume("张三", 20, new ArrayList<>());Resume resume2 = (Resume) resume1.clone();// 引用型变量使用==判等判断的是引用型变量指向地址是否相同System.out.println("两个对象所指向内存地址是否相同:" + (resume1 == resume2));System.out.println("两个对象的成员变量name所指向的内存地址是否相同:" + (resume1.getTechnologyStack() == resume2.getTechnologyStack()));}
}

控制台结果

两个对象所指向内存地址是否相同:false
两个对象的成员变量name所指向的内存地址是否相同:true

深拷贝

在深拷贝中:

  • 无论原型对象的成员变量是基本数据类型还是引用类型,都将复制一份给克隆对象

代码演示

具体原型类

package ProtoType.DeepCopy;import java.io.*;
import java.util.List;/*** @Author: 少不入川* @Date: 2022/11/28 21:58*/
public class Resume implements Serializable {private String name;private int age;private List technologyStack;public Resume(){}public Resume(String name, int age, List technologyStack){this.name = name;this.age = age;this.technologyStack = technologyStack;}public List getTechnologyStack() {return technologyStack;}public void setTechnologyStack(List technologyStack) {this.technologyStack = technologyStack;}public String getName() {return name;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Resume{" +"name='" + name + '\'' +", age=" + age +", technologyStack=" + technologyStack +'}';}public Object deepClone() {//创建流对象ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {//序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);//当前这个对象以对象流的方式输出oos.writeObject(this);//反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);Resume resume = (Resume) ois.readObject();return resume;} catch (Exception e) {e.printStackTrace();return null;} finally {try {bos.close();oos.close();bis.close();ois.close();} catch (Exception e2) {System.out.println(e2.getMessage());}}}}

测试类

package ProtoType.DeepCopy;import java.util.ArrayList;/*** @Author: 少不入川* @Date: 2022/11/28 22:09*/
public class DeepCopyTest {public static void main(String[] args) {Resume resume1 = new Resume("张三", 20, new ArrayList<>());Resume resume2 = (Resume) resume1.deepClone();// 引用型变量使用==判等判断的是引用型变量指向地址是否相同System.out.println("两个对象所指向内存地址是否相同:" + (resume1 == resume2));System.out.println("两个对象的成员变量name所指向的内存地址是否相同:" + (resume1.getTechnologyStack() == resume2.getTechnologyStack()));}
}

控制台输出

两个对象所指向内存地址是否相同:false
两个对象的成员变量name所指向的内存地址是否相同:false

4.原型模式的优点与缺点

  • 优点
    • 当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,可以提高新实例的创建效率
    • 可辅助实现撤销操作,使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用恢复到历史状态
  • 缺点
    • 需要为每一个类配备一个克隆方法,对已有的类进行改造时,需要修改源代码,违背了“开闭原则”

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...