设计模式-创建型模式之原型、建造者设计模式

文章目录

    • 七、原型模式
    • 八、建造者模式

七、原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。它提供了一种创建对象的最佳方式
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

例如:

创建一个可复制的支付类:

public class WxPay implements Cloneable{public WxPay(){System.out.println("创建支付对象");}public WxPay clone() throws CloneNotSupportedException {System.out.println("复制对象!");return (WxPay) super.clone();}
}

使用:

public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.clone();System.out.println(pay);System.out.println(pay1);}
}

在这里插入图片描述

可以看到,创建了两个不同的对象,只进行了一次构件函数的执行,当直接创建对象的代价比较大时,就可以采用这种模式。

另外,原型的拷贝又有浅拷贝深拷贝两个层次,上面的方式就是浅拷贝,只把当前对象做了拷贝,如果对象中有其他对象的引用,就不会进行拷贝,修改任意一个对象中的引用,对其他都会有影响

比如上面的WxPay类做如下修改:

  1. 先定义其他操作类
public class OtherOperation {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  1. 再修改WxPay类
public class WxPay implements Cloneable {private OtherOperation otherOperation = new OtherOperation();public WxPay() {System.out.println("创建支付对象");}public WxPay clone() throws CloneNotSupportedException {System.out.println("复制对象!");return (WxPay) super.clone();}public OtherOperation getOperation() {return otherOperation;}public String getName() {return otherOperation.getName();}}
  1. 演示
public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.clone();System.out.println(pay);System.out.println(pay1);System.out.println(pay.getOperation());System.out.println(pay1.getOperation());pay.getOperation().setName("abc");System.out.println(pay1.getOperation().getName());}
}

在这里插入图片描述

上面可以看出,WxPay确实是复制出了一个实例,但是WxPay里面的OtherOperation实例没有复制,还只向同一个地址,导致只要修改任意一个对象中的OtherOperation对其他实例都会有影响。

上面已经看出默认是浅拷贝,但有的时候,我们又需要其中引用的对象也要为新实例,那怎么做呢,下面就来看下深拷贝的实现方式:

深拷贝实现方式 1:重写 clone 方法来实现深拷贝
深拷贝实现方式 2:通过对象序列化实现深拷贝(推荐)

实现方式 1,重写 clone 方法来实现深拷贝

  1. 修改 OtherOperation类
public class OtherOperation implements Cloneable{private String name;public OtherOperation clone() throws CloneNotSupportedException {System.out.println("复制OtherOperation对象!");return (OtherOperation) super.clone();}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  1. 修改WxPay,在clone中再复制OtherOperation ,以达到深拷贝的效果
public class WxPay implements Cloneable {private OtherOperation otherOperation = new OtherOperation();public WxPay() {System.out.println("创建支付对象");}public WxPay clone() throws CloneNotSupportedException {System.out.println("复制对象!");WxPay wxPay = (WxPay) super.clone();wxPay.otherOperation = otherOperation.clone();return wxPay;}public OtherOperation getOperation() {return otherOperation;}public String getName() {return otherOperation.getName();}}
  1. 演示
public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.clone();System.out.println(pay);System.out.println(pay1);System.out.println(pay.getOperation());System.out.println(pay1.getOperation());pay.getOperation().setName("abc");System.out.println(pay1.getOperation().getName());}
}

在这里插入图片描述

可以看到,WxPay 和 OtherOperation 都是新实例。

深拷贝实现方式 2:通过对象序列化实现深拷贝

  1. OtherOperation 实现 Serializable
public class OtherOperation implements  Serializable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  1. WxPay 实现Serializable,并提供方法对当前对象进行序列化操作
public class WxPay implements Serializable {private OtherOperation otherOperation = new OtherOperation();public WxPay() {System.out.println("创建支付对象");}public OtherOperation getOperation() {return otherOperation;}public String getName() {return otherOperation.getName();}public WxPay 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);return (WxPay) ois.readObject();}catch (Exception e) {return null;}finally {//关闭流try {bos.close();oos.close();bis.close();ois.close();}catch (Exception e2) {System.out.println(e2.getMessage());}}}
}
  1. 效果
public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.deepClone();System.out.println(pay);System.out.println(pay1);System.out.println(pay.getOperation());System.out.println(pay1.getOperation());pay.getOperation().setName("abc");System.out.println(pay1.getOperation().getName());}
}

在这里插入图片描述

和上面我们手动的方式是一样的效果。

八、建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

例如,在游戏场景中,需要构建人物模型,可能要先构建头部、再构建身体、然后四肢部分,最后才是一个完整的人物,如果都写在一起,肯定会导致代码复杂不易其他开发人员理解,对后期维护扩展难度都大,如果使用构建者模式,便可以将头部、身体、四肢,写在不同的人物实现里面,最后由一个构建类去按照一定的顺序加载它们,然后组成了一个更大的复杂的对象,这样便有利于维护扩展。

下面我们借助上面的例子简单用构建者模式实现下

  1. 定义人物对象,这里直接将头、身体、四肢简化为属性的形式表达。
@Data
public class Person {private String head;private String body;private String foot;
}
  1. 定义人物构建接口,并定义具体的抽象方法。
public interface PersonBuilder {//构建入口Person Builder();//构建头部void builderHead();//构建身体void builderBody();//构建四肢void builderFoot();
}
  1. 定义一个男孩人物的具体构建实现
public class BoyBuilder implements PersonBuilder {private Person person;public BoyBuilder() {person = new Person();}@Overridepublic Person Builder() {builderHead();builderBody();builderFoot();System.out.println("构建完成!");return person;}@Overridepublic void builderHead() {System.out.println("开始构建男孩头部...");person.setHead("男孩头部信息");}@Overridepublic void builderBody() {System.out.println("开始构建男孩身体...");person.setBody("男孩身体信息");}@Overridepublic void builderFoot() {System.out.println("开始构建男孩四肢...");person.setFoot("男孩四肢部分信息");}}
  1. 演示
public class demo {public static void main(String[] args) {PersonBuilder personBuilder = new BoyBuilder();Person person = personBuilder.Builder();System.out.println(StringFormatter.concat("构建对象:", person.toString()).getValue());}}

在这里插入图片描述

上面就是将一个人物的不同部分分别构建(实际中每个小的构建都应该在具体的实现中去表达,这里简化为了一个属性),一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

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

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

相关文章

Python实现FA萤火虫优化算法优化循环神经网络回归模型(LSTM回归算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法(Fire-fly algorithm,FA)由剑桥大学Yang于2009年提出 , …

[操作系统] 文件管理

文章目录 5.1 磁盘调度算法1. 先来先服务算法( First Come First Served, FCFS) 算法2. 最短寻道时间优先算法( Shortest Seek Time First, SSTF) 算法3. 扫描算法( SCAN ) 算法4. 循环扫描算法( Circular Scan, CSCAN ) 算法5. LOOK 与 CLOOK 算法 5.2 进程写文件时&#xff0…

禁奥义·SQL秘籍

sql secret scripts sql 语法顺序、执行顺序、执行过程、要点解析、优化技巧。 1、语法顺序 如上图所示,为 sql 语法顺序与执行顺序对照图。其具体含义如下: 0、select: 用于从数据库中选取数据,即表示从数据库中查询到的数据的…

[架构之路-255]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 架构设计 - 软件架构风格

目录 前言: 一、建筑风格 1.1 什么是建筑风格 1.2 常见的建筑风格 1.3 如何区分不同的建筑风格 二、软件架构风格概述 2.1 什么是软件架构风格 2.2 如何区分不同的软件架构风格 2.3 软件架构风格的发展阶段 2.4 软件架构风格与软件架构的区别 2.5 常见的…

数字图像处理(实践篇)十五 基于傅里叶变换的高通滤波和低通滤波

目录 一 Numpy 实现傅里叶变换 1 涉及的函数 2 实践 二 OpenCV 实现傅里叶变换 1 涉及的函数 2 实践 为了有效地和快速地对图像进行处理和分析,常常需要将原定义在图像空间的图像以某种形式转换(正变换)到另外一些空间,并利…

使用gparted进行ubuntu虚拟机的磁盘扩容(解决gparted无法拖动分区的问题)

在学习内核编译下载linux内核源码的时候,由于源码非常大,下载的时候提示磁盘空间不足,我才意识到刚开始创建虚拟机的时候分配了20GB的空间现在已经快用光了。在VM的设置里可以进行扩容,我扩展到了30GB重启却发现空间并没有加到我使…

数据库应用:MongoDB 文档与索引管理

目录 一、理论 1.MongoDB文档管理 2.MongoDB索引管理 二、实验 1.MongoDB文档管理 2.MongoDB索引管理(索引添加与删除) 3.MongoDB索引管理(全文索引) 4.MongoDB索引管理(多列索引) 5.MongoDB索引管…

虚拟数字人有什么用?有哪些应用场景?

​​过去三年,元宇宙概念进入到大众视野,虚拟数字人备受关注。抖音达人柳夜熙、洛天依、网红虚拟偶像AYAYI等,随着元宇宙的流行,数字人也逐渐成为一种趋势。据行业预测,到2030年,中国的数字人总市场规模将达…

APITable免费开源的多维表格与可视化数据库本地部署公网远程访问

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…

我与开源的历程

我在2000年开始接触开源,当时在松下航空电子美国总部工作。我负责将 IFE 系统从 Win31 迁移到 Linux。作为一个完全不懂 Linux 的小白,我不得不找到一台笔记本电脑安装并自学 Redhat Linux 6.1。2003年回到新加坡后,我发现没有一个凝聚 Linux…

最新AI创作系统ChatGPT系统运营源码+DALL-E3文生图+支持OpenAI-GPT全模型+国内AI全模型

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统,支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…

centos7下执行yum命令报错

前言 在Linux系统中,安装nginx时候,需要先安装环境。 Nginx是使用C语言开发,安装nginx需要先从官网上将源码下载,然后编译,编译需要gcc环境,但是在安装gcc环境的时候,执行命令报错。 yum install –y gcc-…

Java零基础——Redis篇

1.【熟悉】NoSQL的简介 1.1 什么是NoSQL NoSQL 是 Not Only SQL 的缩写,意即"不仅仅是SQL"的意思,泛指非关系型的数据库。强调Key-Value Stores和文档数据库的优点。 NoSQL产品是传统关系型数据库的功能阉割版本,通过减少用不到或…

易宝OA ExecuteSqlForSingle SQL注入漏洞复现

0x01 产品简介 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台,具有信息管理、 流程管理 、知识管理(档案和业务管理)、协同办公等多种功能。 0x02 漏洞概述 易宝OA ExecuteSqlForSingle接口处存在SQL注入漏洞&a…

qt 5.15.2压缩和解压缩功能

qt 5.15.2压缩和解压缩功能 主要是添加qt项目文件.pro内容: 这里要先下载quazip的c项目先编译后引入到本项目中/zip目录下 INCLUDEPATH ./zip CONFIG(debug, debug|release) {win32:win32-g: PRE_TARGETDEPS $$PWD/zip/libquazipd.awin32:win32-g: LIBS -L$$PWD…

基于Netty的网络调用实现

作为一个分布式消息队列,通信的质量至关重要。基于TCP协议和Socket实现一个高效、稳定的通信程序并不容易,有很多大大小小的“坑”等待着经验不足的开发者。RocketMQ选择不重复发明轮子,基于Netty库来实现底层的通信功能。 1 Netty介绍 Net…

【pytorch】深度学习入门一:pytorch的安装与配置(Windows版)

请支持原创,认准DannisTang(tangweixuan1995foxmail.com) 文章目录 第〇章 阅读前提示第一章 准备工作第一节 Python下载第二节 Python安装第三节 Python配置第四节 Pycharm下载第五节 Pycharm安装第六节 CUDA的安装 第二章 Anaconda安装与配…

Gitee 之初体验(上)

我们在项目开发或者自己学习的时候,总会存在这样的问题: 在一台电脑上编写完代码,想要再另外一台电脑上再去写,再或者和其他人一起协作等等场合,代码传来传去很麻烦。 这个时候,我们就可以去使用代码管理工…

LeetCode刷题---打家劫舍问题

顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、打家劫舍 题目链接:打家劫舍 题目描述 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定…

Spring Security 6.x 系列(7)—— 源码分析之建造者模式

一、建造者模式 WebSecurity、HttpSecurity、AuthenticationManagerBuilder 都是框架中的构建者,把他们放到一起看看他们的共同特点: 查看AuthenticationManagerBuilder的继承结构图: 查看HttpSecurity的继承结构图: 查看WebSec…