设计模式-创建型
文章目录
- 设计模式-创建型
- 工厂模式
- 简单工厂
- 工厂方法
- 抽象工厂
- 建造者模式
- 单例模式
- 原型模式
设计模式-创建型
本章主要介绍有关对象创建的几种设计模式。
工厂模式
工厂模式:封装了对象的创建,使得获得对象更加符合实际逻辑
简单工厂
将所有对象的生产集中到一个工厂中
根据传参确定生产的对象类型
public abstract class Fruit { private final String name;public Fruit(String name){this.name = name;}@Overridepublic String toString() {return name+"@"+hashCode();}
}
public class Apple extends Fruit{ public Apple() {super("苹果");}
}
public class Orange extends Fruit{ public Orange() {super("橘子");}
}
public class FruitFactory {public static Fruit getFruit(String type) {switch (type) {case "苹果":return new Apple();case "橘子":return new Orange();default:return null;}}
}
缺点:
逻辑不符合:一个工厂一般只是单一生产
工厂设计不封闭:增加和减少生产对象需要对原来代码进行修改,不符合软件设计的开闭原则
工厂方法
将工厂划分成一个继承机构,基类工厂提供了生产对象虚函数接口,而派生类代表生产某种对象的工厂,重写基类提供的虚函数接口,返回生产的对象
public abstract class FruitFactory<T extends Fruit> {public abstract T getFruit();
}
public class AppleFactory extends FruitFactory<Apple> { @Overridepublic Apple getFruit() {return new Apple();}
}
这样就可以使用不同类型的工厂来生产不同类型的水果了,并且如果新增了水果类型,直接创建一个新的工厂类就行,不需要修改之前已经编写好的内容。
缺点:
一个系列产品一个工厂结构,一种基类只能派生具有关联关系的生产工厂,不同类的需要构建其他的继承工厂结构
优点:
-
符合实际逻辑
-
符合开闭原则
抽象工厂
对有一组关联关系的产品簇提供产品的统一创建,即一个工厂生产一组相关联的产品
建立一个抽象工厂,一个实例工厂可以生产同一个产品簇的所有产品
public class Router {
}
public class Table {
}
public class Phone {
}
public abstract class AbstractFactory {public abstract Phone getPhone();public abstract Table getTable();public abstract Router getRouter();
}
所有的派生类需要重写所有的基类提供的虚函数接口
- 总结:
- 简单工厂simple Factory :
优点:把对象的创建封装在一个接口函数里面,通过传入不同的标识,返回创建的对象,客户不用自己负责new对象,不用了解对象创建的详细过程
缺点:不符合实际生产逻辑,提供创建对象实例的接口函数不闭合,不能对修改关闭
- 工厂方法Factory Method:
优点:Factory基类,提供了一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建对应的产品(重写虚函数),可以做到不同的产品,在不同的工厂里面创建,能够对现有工厂,以及产品的修改关闭(符合软件开闭原则)
缺点:实际上,很多产品是有关联关系的,属于一个产品簇,不应该放在不同的工厂里面去创建,这样一是不符合实际的产品对象创建逻辑,二是工厂类太多了,不好维护
- 抽象工厂Abstract Factory:
把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面Abstract Factory,派生类(具体产品的工广)应该负责创建该产品簇里面所有的产品
所有派生类对基类提供的纯虚函数接口都要进行重写
建造者模式
有很多的框架都为我们提供了形如XXXBuilder
的类型,一般可以使用这些类来创建我们需要的对象。
例如StringBuiler
类:
public static void main(String[] args) {StringBuilder builder = new StringBuilder(); //创建一个StringBuilder来逐步构建一个字符串builder.append(666); //拼接一个数字builder.append("老铁"); //拼接一个字符串builder.insert(2, '?'); //在第三个位置插入一个字符System.out.println(builder.toString()); //转换为字符串
}
通过建造者来不断配置参数或是内容,当我们配置完所有内容后,最后再进行对象的构建。
相比直接去new一个新的对象,建造者模式的重心更加关注在如何完成每一步的配置,如果一个类的构造方法参数过多,通过建造者模式来创建这个对象,会更加优雅。
案例:
public class Student {...//一律使用建造者来创建,不对外直接开放private Student(int id, int age, int grade, String name, String college, String profession, List<String> awards) {...}public static StudentBuilder builder(){ //通过builder方法直接获取建造者return new StudentBuilder();}public static class StudentBuilder{ //这里就直接创建一个内部类//Builder也需要将所有的参数都进行暂时保存,所以Student怎么定义的这里就怎么定义int id;int age;int grade;String name;String college;String profession;List<String> awards;public StudentBuilder id(int id){ //直接调用建造者对应的方法,为对应的属性赋值this.id = id;return this; //为了支持链式调用,这里直接返回建造者本身,下同}public StudentBuilder age(int age){this.age = age;return this;}...public StudentBuilder awards(String... awards){this.awards = Arrays.asList(awards);return this;}public Student build(){ //最后我们只需要调用建造者提供的build方法即可根据我们的配置返回一个对象return new Student(id, age, grade, name, college, profession, awards);}}
}
使用建造者来为生成学生对象:
public static void main(String[] args) {Student student = Student.builder() //获取建造者.id(1) //逐步配置各个参数.age(18).grade(3).name("小明").awards("ICPC", "LPL").build(); //最后直接建造我们想要的对象
}
单例模式
单例模式即在我们的整个程序中,同一个类始终只会有一个对象来进行操作。
饿汉单例:在一开始类加载时就创建好了
public class Singleton {private final static Singleton INSTANCE = new Singleton(); //用于引用全局唯一的单例对象,在一开始就创建好private Singleton() {} //不允许随便new,需要对象直接找getInstancepublic static Singleton getInstance(){ //获取全局唯一的单例对象return INSTANCE;}
}
懒汉单例:延迟加载,当我们需要获取对象时,才会进行检查并创建。
由于懒汉式是在方法中进行的初始化,在多线程环境下,可能会出现问题
public class Singleton {private static volatile Singleton INSTANCE; //volatile保证线程可见性private Singleton() {} public static Singleton getInstance(){if(INSTANCE == null) {//减低锁竞争synchronized (Singleton.class) {//保证线程安全if(INSTANCE == null) INSTANCE = new Singleton(); }}return INSTANCE;}
}
不用加锁懒汉模式:
public class Singleton {private Singleton() {}private static class Holder { //由静态内部类持有单例对象,但是根据类加载特性,我们仅使用Singleton类时,不会对静态内部类进行初始化private final static Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){ //只有真正使用内部类时,才会进行类初始化return Holder.INSTANCE; //直接获取内部类中的}
}
原型模式
原型模式实际上与对象的拷贝息息相关,原型模式使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象
- **浅拷贝:**对于类中基本数据类型,会直接复制值给拷贝对象;对于引用类型,只会复制对象的地址。
- **深拷贝:**无论是基本类型还是引用类型,深拷贝会将引用类型的所有内容,全部拷贝为一个新的对象,包括对象内部的所有成员变量,也会进行拷贝。
在Java中,通过实现Cloneable接口来实现原型模式:
Java为我们提供的clone
方法对对象成员只会进行浅拷贝,要实现深拷贝需要进一步完成如何拷贝
public class Student implements Cloneable{String name;public Student(String name){this.name = name;}public String getName() {return name;}@Overridepublic Object clone() throws CloneNotSupportedException { //针对成员变量也进行拷贝Student student = (Student) super.clone();student.name = new String(name);return student; }
}
相关文章:
设计模式-创建型
文章目录 设计模式-创建型工厂模式简单工厂工厂方法抽象工厂 建造者模式单例模式原型模式 设计模式-创建型 本章主要介绍有关对象创建的几种设计模式。 工厂模式 工厂模式:封装了对象的创建,使得获得对象更加符合实际逻辑 简单工厂 将所有对象的生产…...

Word通过Adobe打印PDF时总是报错,打开记事本
Word文档打印,选择Adobe作为打印机,打印过程中总是报错,不断打开记事本,提示打印出错,错误信息如下: %%[ ProductName: Distiller ]%% %%[Page: 1]%% %%[Page: 2]%% %%[ Error: invalidfont; OffendingCom…...

第2关:还原键盘输入(list)
题目: 知识点: 列表list相较于数组: 优势:可在任意指定位置插入或者删除元素而不影响列表其他地方 。 劣势:无法直接进行下标索引,需要迭代器it逐个遍历。 代码: #include <iostream>…...

数据结构 | 栈的实现
数据结构 | 栈的实现 文章目录 数据结构 | 栈的实现栈的概念及结构栈的实现 Stack.h初始化栈入栈出栈获取栈顶元素获取栈中有效元素个数检测栈是否为空销毁栈 Stack.c 栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。…...

python异常、模块与包
1.异常 异常:当检测到一个错误时,Python解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”,也就是我们常说的BUG。 1.1捕获异常 基本语法: try:可能发生错误代码 except:如果出现…...
虚拟内存和物理内存
虚拟内存的概念 虚拟内存是计算机系统内存管理的一种技术,它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储…...
FCA例题
Part.1:判断题 第1题 智能运维-负载管理中,实时负载通过使用图表直观的展示当前系统的最多最近半小时内存利用率和CPU利用率(正确) 第2题 服务器安装插件支持热部署,安装、删除、更新、禁用、启用不需要重启(正确) 第3题 次级管理员可新建…...
mysql使用GROUP BY归组后把所有记录id汇总到一个字段中
可以使用MySQL的GROUP_CONCAT函数来实现将归组后的记录的ID汇总到一个字段中。假设有一个名为table1的表,其中包含id和name两个字段,可以使用以下查询: SELECT name, GROUP_CONCAT(id) AS ids FROM table1 GROUP BY name;这将返回一个结果集…...
Vue3 使用Element Plus表格单选带checkbox
官方地址:添加链接描述 官方给出的多选带checkbox,单选直接选中当前行高亮,有时候不想要单行高亮,想要带checkbox的单选,需要对多选进行改造 官方给的多选例子: <template><el-tableref"mult…...
IOC - 自定义IOC容器
1、定义接口与实现类 // Service接口 public interface Service {void execute(); } // Service的实现类 public class MyService implements Service {Overridepublic void execute() {System.out.println("MyService 执行了.");} }2、自定义ioc容器以绑定接口与实…...

力扣第647题 回文子串 c++ 动态规划 双指针 附Java代码 注释解释版
题目 647. 回文子串 中等 相关标签 字符串 动态规划 给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串…...

【Go入门】struct类型
【Go入门】struct类型 struct Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其它类型的属性或字段的容器。例如,我们可以创建一个自定义类型person代表一个人的实体。这个实体拥有属性:姓名和年龄。这样…...

怎么改变容易紧张的性格?
容易紧张的性格是比较通俗的说法,在艾森克人格测试中,容易紧张的性格就属于神经症人格,神经质不是神-经-病,而是一种人格特征,这种特征包括:敏感,情绪不稳定,易焦虑和紧张。有兴趣的…...

合作共赢 共克时艰
采访人:最近财政部11月6日通报隐性债务问责典型案例,这中间涉及湖北多所重要地市,形成新增隐性债务200多亿,您怎么看这件事? 辜渝傧:是的,无论是数字还是涉及的范围都可以明显感觉到“防范…...
VCSA7许可证过期问题
公司两台ESXI7虚拟化系统,使用VCSA7进行日常管理,在使用过程中一直清单中包含过期或即将过期的许可证。 查看许可证清单中,已经添加了正式授权的许可证,且已经分配给了ESXI主机,但是任然有到期提示。 最后查看试用许可…...

解决win11更新后,文件夹打不开的bug
更新win11系统了,给我更了个bug,找了好多解决方案,发现下面这个可以解决问题。 第一步 找到注册表 第二步 备份注册表 为了防止意外情况,备份注册表。如有意外问题,可以导入导出的注册表进行恢复。 第三步 删除指定…...

修复了数个Bug!
v2.0.1版本已经在 github release 了,欢迎大家体验使用,开源版是永久免费的。 ## 新增与优化的功能 新增(测试报告): 测试报告根据测试执行详情,进行查看 新增(用户设置): 用户权限为普通用户和管理员,普通用户根据设置的默认产品…...

设计模式之--原型模式(深浅拷贝)
原型模式 缘起 某天,小明的Leader找到小明:“小明啊,如果有个发简历的需求,就是有个简历的模板,然后打印很多份,要去一份一份展示出来,用编程怎么实现呢?” 小明一听,脑袋里就有了…...

Linux服务器从零开始训练 RT-DETR 改进项目 (Ultralytics) 教程,改进RTDETR算法(包括使用训练、验证、推理教程)
手把手从零开始训练 RT-DETR 改进项目 (Ultralytics版本) 教程,改进RTDETR算法 本文以Linux服务器为例:从零开始使用Linux训练 RT-DETR 算法项目 《芒果剑指 RT-DETR 目标检测算法 改进》 适用于芒果专栏改进RT-DETR算法 文章目录 百度 RT-DETR 算法介绍改进网络代码汇总第…...
矩阵理论--矩阵分解
矩阵理论–矩阵分解 矩阵的三角分解、谱分解、最大秩分解、奇异值分解的操作步骤,以及相关说明。 1、QR分解 (1)非奇异方阵 方阵(非奇异):将方阵分解成酉矩阵左乘正线上三角,或者酉矩阵右乘…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...