设计模式05-创建型模式(建造者/原型/单例模式/Java)

3.4 建造者模式

3.4.1 建造者模式的定义

动机:方便创建复杂对象(一个对象中包含多个成员变量)

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

3.4.2 建造者模式的分析与实现

image-20241019182144932

  • 产品类:复杂对象,里面包含多个成员变量
public class Product {private String part1;private String part2;public String getPart1() {return part1;}public void setPart1(String part1) {this.part1 = part1;}public String getPart2() {return part2;}public void setPart2(String part2) {this.part2 = part2;}
}
  • 建造者类:内含两类方法,一个是建造构件,一个是返回建造对象
public abstract class Builder {protected Product product = new Product();public abstract void buildPartA();public abstract void buildPartB();public abstract Product getResult();
}public class ConcreteBuilderA extends Builder{@Overridepublic void buildPartA() {product.setPart1("部件A");}@Overridepublic void buildPartB() {product.setPart2("部件B");}@Overridepublic Product getResult() {return product;}
}
  • 指挥者类:负责构建的建造次序,并返回产品类
public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}public Product construct() {builder.buildPartA();builder.buildPartB();return builder.getResult();}
}
  • 客户端类:只需要指定具体的建造者即可,无需关心产品的具体组装过程
public class Main {public static void main(String[] args) {Director director = new Director(new ConcreteBuilderA());Product construct = director.construct();System.out.println(construct.getPart1());System.out.println(construct.getPart2());}
}
3.4.3 建造者模式案例

建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。

image-20241019184000936
  • 产品类
public class Meal {private String food;private String drink;public String getFood() {return food;}public void setFood(String food) {this.food = food;}public String getDrink() {return drink;}public void setDrink(String drink) {this.drink = drink;}
}
  • 建造者类
public interface MealBuilder {public void buildFood();public void buildDrink();public Meal getMeal();
}public class MealBuilder1 implements MealBuilder {private Meal meal = new Meal();@Overridepublic void buildFood() {meal.setFood("汉堡");}@Overridepublic void buildDrink() {meal.setDrink("可乐");}@Overridepublic Meal getMeal() {return meal;}
}public class MealBuilder2 implements MealBuilder {private Meal meal = new Meal();@Overridepublic void buildFood() {meal.setFood("鸡肉卷");}@Overridepublic void buildDrink() {meal.setDrink("果汁");}@Overridepublic Meal getMeal() {return meal;}
}
  • 指挥者类
public class KFCWaiter {private MealBuilder mealBuilder;public void setMealBuilder(MealBuilder mealBuilder) {this.mealBuilder = mealBuilder;}public Meal constructMeal() {mealBuilder.buildFood();mealBuilder.buildDrink();return mealBuilder.getMeal();}
}
  • 客户端
public class Main {public static void main(String[] args) {MealBuilder2 mealBuilder= (MealBuilder2) XMLUtilMeal.getMealMethod();KFCWaiter kfcWaiter = new KFCWaiter();kfcWaiter.setMealBuilder(mealBuilder);Meal meal = kfcWaiter.constructMeal();System.out.println("套餐2");System.out.println("主食为:" + meal.getFood());System.out.println("饮品为:" + meal.getDrink());}
}
3.4.4 建造者模式的优缺点
优点缺点
1.实现了产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象,精细地控制产品的创建过程1.同一个抽象构造者只适用构建一类型相同的产品,若产品间差别太大不适用
2.由于引入抽象建造者,因此很容易引入新的创建者,符合开闭原则2.产品内部构造复杂,会引起系统庞大,难以构建
3.4.5 建造者模式的适用场景
  • 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量,且需要生成的产品对象的属性相互依赖,需要指定其生成顺序

  • 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中

3.5 原型模式

3.5.1 原型模式的定义

动机:有些对象的创建过程较为复杂,而且需要频繁创建。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。原型模式允许通过一个原型对象创建一个或多个同类型的其他对象,而无须知道任何创建的细节

3.5.2 原型模式的分析与实现

将一个原型对象传给要发动创建的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程。创建新对象(也称为克隆对象)的工厂就是原型类自身,工厂方法由负责复制原型对象的克隆方法来实现。通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,每一个克隆对象都是独立

image-20241019193531286
  • 浅克隆:只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制
image-20241019193926199

在Java中可以直接使用Object提供的clone()方法来实现对象的克隆(浅克隆)

能够实现克隆的Java类必须实现一个标识接口Cloneable,表示这个Java类支持复制

如果一个类没有实现这个接口但是调用了clone()方法,Java编译器将抛出一个CloneNotSupportedException异常

public class ShallowPrototype implements Cloneable{public String name;@Overridepublic ShallowPrototype clone() {try {return (ShallowPrototype) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}
  • 深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制
image-20241019193952167

如果需要实现深克隆,可以通过序列化等方式来实现。在Java语言中,序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。**通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,从而实现深克隆。**需要注意的是,能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

public class DeepPrototype implements Serializable {public String name = "sda";public DeepPrototype clone() {try {//将对象写到输入流中ByteArrayOutputStream bao = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bao);oos.writeObject(this);//将对象从输入流中取出ByteArrayInputStream bais = new ByteArrayInputStream(bao.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);return (DeepPrototype) ois.readObject();} catch (Exception e) {throw new RuntimeException(e);}}
}
  • 克隆的结果
1)对任何的对象x,都有x.clone()!=x,即克隆对象与原对象不是同一个对象。
(2)对任何的对象x,都有x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型一样。
3.5.3 原型模式的案例

由于邮件对象包含的内容较多(如发送者、接收者、标题、内容、日期、附件等),某系统中现需要提供一个邮件复制功能,对于已经创建好的邮件对象,可以通过复制的方式创建一个新的邮件对象,如果需要改变某部分内容,无须修改原始的邮件对象,只需要修改复制后得到的邮件对象即可。使用原型模式设计该系统。

浅克隆:

image-20241019201056294
public class EmailPrototype implements Cloneable {private File file = null;public EmailPrototype() {this.file = new File();}public void display() {System.out.println("展示所下载的文件");}public File getFile() {return this.file;}public EmailPrototype close() {try {return (EmailPrototype) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}

深克隆:

image-20241019201113430

public class EmailPrototype implements Serializable {private File file = null;public EmailPrototype() {this.file = new File();}public void display() {System.out.println("展示所下载的文件");}public File getFile() {return this.file;}public EmailPrototype deepClone() {try {//将对象转化写入到字节流中ByteArrayOutputStream bao = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bao);oos.writeObject(this);//将对象从字节流中取出ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (EmailPrototype) ois.readObject();} catch (Exception e) {throw new RuntimeException(e);}}
}
3.5.4 原型模式的优缺点
优点缺点
1.简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率1.需要为每一个类配备一个克隆方法,当对已有的类进行改造时,需要修改源代码,违背了开闭原则。
2.可以使用深克隆的方式保存对象的状态,以便在需要的时候使用,可辅助实现撤销操作
3.对于相似的对象,可以修改其属性使得各对象不同
3.5.5 原型模式的适用场景
  • 创建新对象成本较大,新对象可以通过复制已有对象来获得,如果是相似对象,则可以对其成员变量稍作修改

  • 系统要保存对象的状态,而对象的状态变化很小

  • 需要避免使用分层次的工厂类来创建分层次的对象

3.5.6 原型模式的扩展

通过原型管理器,管理所有可以复制的对象

将多个原型对象存储在一个集合中供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得。

image-20241019201624755
public class PrototypeManager {private Hashtable prototypeTable=new Hashtable();  //Hashtable存储原型对象public PrototypeManager() {prototypeTable.put("A", new ConcretePrototypeA());prototypeTable.put("B", new ConcretePrototypeB());}   public void add(String key, Prototype prototype) {prototypeTable.put(key,prototype);} public Prototype get(String key) {Prototype clone = null;clone = ((Prototype)prototypeTable.get(key)).clone(); //克隆方法创建新对象return clone;}    
}

3.6 单例模式

3.6.1 单例模式的定义

动机:如何确保一个类只有一个实例并且这个实例易于被访问

定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类

3.6.2 单例模式的分析与实现

image-20241019202136689

  • 唯一实例:为了防止客户端程序使用构造函数来创建多个对象,可以将构造函数声明为私有的,这样客户端程序就不可以使用它来创建任何对象。

  • 提供访问:通过创建一个全局变量和一个getInstance()静态方法,用来让外部客户端访问

  • 分类:

**懒汉式:**该模式只在你需要对象时才会生成单例对象(比如调用getInstance方法)

public class Singleton1 {private static Singleton1 singleton = null;private Singleton1() {}public static Singleton1 get() {if (singleton == null) {singleton = new Singleton1();} else {System.out.println("此对象已经被创建过了");}return singleton;}
}

**饿汉式:**该模式在类被加载时就会实例化一个对象。

public class Singleton2 {private static Singleton2 singleton = new Singleton2();private Singleton2() {}public static Singleton2 get() {return singleton;}
}
懒汉式饿汉式
实例化外部调用时类加载时
线程安全不安全安全
执行效率较低较高
内存不浪费浪费
3.6.3 单例模式的案例

在操作系统中,打印池(Print Spooler)是一个用于管理打印任务的应用程序,通过打印池用户可以删除、中止或者改变打印任务的优先级,在一个系统中只允许运行一个打印池对象,如果重复创建打印池则抛出异常。现使用单例模式来模拟实现打印池的设计。

image-20241019203315755
public class Printer {private static Printer printer = null;private Printer() {}public static Printer getInstance() {if (printer == null) {System.out.println("获取打印机资源");printer = new Printer();} else {try {System.out.println("打印机资源已被占用");int x = 1/0;} catch (Exception e) {throw new RuntimeException("等待打印机释放资源");}}return printer;}public void manage() {System.out.println("打印机正常工作");}public void revoke() {printer = null;}
}
3.6.4 单例模式的优缺点
优点缺点
1.提供唯一实例的受控访问1.扩展困难
2.节约资源2.单例类的职责过重,违背“单一职责原则”
3.允许可变数目的实例3.由于自动垃圾回收机制,可能会导致共享的单例对象的状态丢失
3.6.5 单例模式的适用场景
  • 系统只需要一个实例对象,或者因为资源消耗太大而只允许创建一个对象

  • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例

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

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

相关文章

计算机视觉中的最小二乘法:寻找完美交点和直线拟合

Hello,小伙伴们!今天我们要聊的是计算机视觉中的一个小技巧——使用最小二乘法来进行交点计算和直线拟合。你有没有想过,如何从一堆杂乱无章的数据点中找到那条最佳拟合直线?或者,如何确定几条直线相交的确切位置&…

OpenCV物体跟踪:使用CSRT算法实现实时跟踪

目录 简介 CSRT算法简介 实现步骤 1. 初始化摄像头和跟踪器 2. 读取视频帧和初始化跟踪 3. 实时跟踪和显示结果 4. 显示和退出 5、结果展示 总结 简介 在计算机视觉和视频处理领域,物体跟踪是一项核心技术,它在监控、人机交互、运动分析等方面…

CSS布局/简单应用

思考下面四个图片如何布局 test1 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</titl…

双十一有啥好用的物品可以推荐购买?2024不可错过的必囤好物清单!

双十一购物狂欢节即将拉开帷幕&#xff0c;许多朋友们可能还在犹豫不决&#xff0c;不知道应该选购哪些商品。别担心&#xff0c;今天我特意为大家精心准备了一份包含五款必囤好物的清单&#xff0c;希望能够帮助大家在双十一期间抢购到心仪的商品&#xff0c;享受购物的乐趣&a…

《米小圈动画成语》|在趣味中学习,在快乐中掌握成语知识!

作为一名家长&#xff0c;我一直希望孩子能够在学习的过程中既感受到乐趣&#xff0c;又能获得真正的知识。成语作为中华文化的精华&#xff0c;虽然意义深远、简洁凝练&#xff0c;但对于一个小学生来说&#xff0c;学习和理解这些言简意赅的成语无疑是一个挑战。尤其是有些成…

将本地文件上传到GIT上

上传文件时&#xff0c;先新建一个空文件&#xff0c;进行本地库初始化&#xff0c;再进行远程库克隆&#xff0c;将要上传的文件放到克隆下来的文件夹里边&#xff0c;再进行后续操作 1.在本地创建文件夹&#xff0c;将要上传的文件放在该文件下 2.在该文件页面中打开Git Bas…

ai字幕用什么软件制作?6款视频加字幕工具分享!

在视频制作和后期处理中&#xff0c;字幕的添加是一个重要的环节。随着AI技术的发展&#xff0c;越来越多的软件开始支持AI自动加字幕功能&#xff0c;使得字幕的制作变得更加简单和高效。本文将为大家介绍几款常用的AI字幕制作软件&#xff0c;并详细讲解如何使用AI自动加字幕…

TDD(测试驱动开发)是否已死?

Rails 大神、创始人 David Heinemeier Hansson 曾发文抨击TDD。 TDD is dead. Long live testing. (DHH) 此后, Kent Beck、Martin Fowler、David Hansson 三人就这个观点还举行了系列对话&#xff08;辩论&#xff09; Is TDD Dead? 笔者作为一个多年在软件测试领域摸索的人&…

Linux——动态卷的管理

确保已经设置了对应的动态卷的驱动&#xff08;provisioner 制备器&#xff09;基于动态驱动创建对应的存储类创建PVC &#xff08;PVC 将会自动根据大小、访问模式等创建PV&#xff09;Pod的spec 中通过volumes 和 volumemounts 来完成pvc 的绑定和pvc对应pv的挂载删除pod 不…

Java基于微信小程序的公考学习平台的设计与实现,附源码+文档

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

新魔百和cm311-5 ZG 4+16g 卡刷语音固件教程

新魔百和cm311-5_国科6323_蓝牙版刷 准备工具&#xff1a;U盘、短接工具、 固件包&#xff1a;CM311-5-zg链接 https://pan.baidu.com/s/1f5NxmCGCO0F84RQRBrSMRg 提取码: b7f1 操作步骤&#xff1a; 1、用不大于8G U盘&#xff0c;先做FAT32&#xff0c;2048块单分区格式化后…

Yoga Pro 13s 2021款Intel处理器ITL版(82HJ)原厂Win10系统镜像下载

lenovo联想Yoga-PRO-13S笔记本电脑恢复开箱状态预装OEM系统Windows10安装包 链接&#xff1a;https://pan.baidu.com/s/1YjGCXe_Zxkwcgum3TWZx5g?pwdshqu 提取码&#xff1a;shqu 联想原装系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、O…

桂林旅游一点通:SpringBoot平台应用

3系统分析 3.1可行性分析 通过对本桂林旅游景点导游平台实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本桂林旅游景点导游平台采用SSM框架&#xff0c;JAVA作…

C++虚函数的默认参数是静态绑定还是动态绑定

C虚函数的默认参数是静态绑定还是动态绑定 或者问&#xff1a;是在编译阶段确定的还是在运行阶段确定的 答案是&#xff1a;编译阶段&#xff0c;也就是静态绑定的 #include <iostream>class Base { public:virtual void func(int x 10) {std::cout << "Ba…

pikachu靶场CSRF-get测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、抓包使用burp生成csrf脚本 四、源代码分析 五、结论 一、测试环境 1、系统环境 渗透机&#xff1a;本机(127.0.0.1) 靶 机&#xff1a;本机(127.0.0.1) 2、使用工具/软件 Burp sui…

字节跳动实习生投毒自家大模型细节曝光 影响到底有多大?

10月19日&#xff0c;字节跳动大模型训练遭实习生攻击一事引发广泛关注。据多位知情人士透露&#xff0c;字节跳动某技术团队在今年6月遭遇了一起内部技术袭击事件&#xff0c;一名实习生因对团队资源分配不满&#xff0c;使用攻击代码破坏了团队的模型训练任务。 据悉&#xf…

信息学竞赛:是靠努力,还是靠天赋?

信息学竞赛&#xff08;OI&#xff09;近年来在学生和家长中越来越受欢迎。这项竞赛不仅可以培养孩子的编程能力和逻辑思维能力&#xff0c;还为一些有志于名校的学生提供了一条升学的捷径。然而&#xff0c;许多人会问&#xff1a;参加信息学竞赛成功的关键在于天赋还是努力&a…

TwinCAT3 软件介绍

文章目录 软件界面各个窗口说明如下图&#xff1a; 工具栏说明如下&#xff1a; 调试按钮说明如下&#xff1a; TwinCAT运行环境按钮说明如下&#xff1a; PLC项目环境说明如下&#xff1a; TwinCAT系统状态图标说明如下&#xff1a; PLC程序状态说明如下&#xff…

机器学习:opencv--人脸检测以及微笑检测

目录 前言 一、人脸检测的原理 1.特征提取 2.分类器 二、代码实现 1.图片预处理 2.加载分类器 3.进行人脸识别 4.标注人脸及显示 三、微笑检测 前言 人脸检测是计算机视觉中的一个重要任务&#xff0c;旨在自动识别图像或视频中的人脸。它可以用于多种应用&#xff0…

[LeetCode] 542. 01矩阵

题目描述&#xff1a; 给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出…