用静态工厂方法代替构造器
用静态工厂方法来代替构造方法。
public class Student {private String name;private int age;private String studentId;private Student(String name, int age, String studentId) {this.name = name;this.age = age;this.studentId = studentId;}public static Student createStudent(String name, int age, String studentId) {// 在静态工厂方法中执行一些额外的逻辑// 例如参数验证、生成默认的学生ID等// 调用私有构造器创建学生对象return new Student(name, age, studentId);}// Getter 和 Setter 方法...}
静态工厂方法相较于构造方法的五个优点:
- 有自己的名称,而构造方法必须与类名一致。
- 不用每次被调用时都会创建一个新的对象,它可以返回预先构造好的对象。
- 可以返回所声明的返回类型的任何子类型的对象。
- 所返回对象的类可以输入的参数不同而改变。
- 在编写包含该方法的类时,所返回对象的类并不一定存在。
缺点:
- 如果没有共有的或者受保护的构造方法,就无法为这些类创建子类。(因祸得福)
- 在API文档中可能会很难发现这个方法。(无伤大雅)
下面来详细谈一谈每一个优缺点:
优点一:
静态工厂方法有自己的名称,而构造方法必须与类名一致:
import java.time.LocalDate;public class DateUtils {private DateUtils() {// 私有构造方法,防止实例化}public static LocalDate createToday() {// 创建表示当前日期的对象return LocalDate.now();}public static LocalDate createDate(int year, int month, int day) {// 创建指定年月日的日期对象return LocalDate.of(year, month, day);}
}
优点二:
静态工厂方法不用每次被调用时都会创建一个新的对象,它可以返回预先构造好的对象:
单例模式(Singleton Pattern)是一种创建型设计模式,旨在确保类只有一个实例,并提供全局访问点以访问该实例。
单例模式的主要特点是:
- 保证类只有一个实例:通过限制类的实例化过程,确保在程序运行期间只存在一个实例对象。
- 全局访问点:提供一个全局的访问方法,使其他对象可以方便地获取该单例实例。
使用单例模式的主要优点包括:
- 对资源的集中管理:单例模式可以集中管理某些共享的资源,确保资源的一致性和可靠性。
- 节约系统资源:由于只有一个实例存在,可以减少系统开销,节约内存和处理器等资源。
- 简化对象之间的通信:通过单例对象,可以简化对象之间的通信,避免了传递多个对象引用的复杂性。
常见的单例模式实现方式有两种:它们的区别在于对象的创建时间点不同。
饿汉模式(Eager Initialization):
- 在类加载时就创建并初始化单例对象。
- 对象在整个生命周期中都存在,无论是否被使用。
- 线程安全,不需要考虑多线程环境。
- 简单直接,但可能导致资源浪费。
懒汉模式(Lazy Initialization):
- 在需要时才创建并初始化单例对象。
- 对象在首次使用时创建,延迟了对象的实例化时间。
- 需要考虑多线程环境下的线程安全性。
- 在多线程环境下可能需要额外的同步机制,可能会影响性能。
// 饿汉模式
public class Singleton {private static Singleton instance = new Singleton();private Singleton() {// 私有构造函数}public static Singleton getInstance() {return instance;}// 其他方法...
}
// 懒汉模式
public class Singleton {private static Singleton instance;private Singleton() {// 私有构造函数}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}// 其他方法...
}
优点三:
静态工厂方法可以返回所声明的返回类型的任何子类型的对象:
举个例子:createShape静态工厂方法声明的返回值类型是Shape,但它却可以返回Shape的子类型Circle和Square。
public class Shape {private String name;private Shape(String name) {this.name = name;}public String getName() {return name;}public static Shape createShape(String name) {if (name.equalsIgnoreCase("circle")) {return new Circle();} else if (name.equalsIgnoreCase("square")) {return new Square();} else {return new Shape(name);}}
}public class Circle extends Shape {public Circle() {super("Circle");}
}public class Square extends Shape {public Square() {super("Square");}
}
java.util.Collections
是 Java 标准库中提供的一个实用类,它包含了一系列静态方法,用于操作和处理集合类(如 List、Set、Map 等)的工具方法。这些方法包括创建不可修改的集合、集合的排序、查找元素、线程安全包装等,其中的很多方法也是返回了所声明的类型的子类型。以下是一些
java.util.Collections
类中常用的静态工厂方法:
创建不可修改的集合(Immutable Collections):
emptyList()
:返回一个空的不可修改的List
。emptySet()
:返回一个空的不可修改的Set
。emptyMap()
:返回一个空的不可修改的Map
。unmodifiableList(List<? extends T> list)
:返回一个不可修改的List
,基于指定的列表。unmodifiableSet(Set<? extends T> set)
:返回一个不可修改的Set
,基于指定的集合。unmodifiableMap(Map<? extends K, ? extends V> map)
:返回一个不可修改的Map
,基于指定的映射。集合的排序和查找:
sort(List<T> list)
:对指定的列表进行原地排序(升序)。reverse(List<T> list)
:反转指定列表中元素的顺序。shuffle(List<T> list)
:随机打乱指定列表中元素的顺序。binarySearch(List<? extends Comparable<? super T>> list, T key)
:二分查找指定列表中的元素。binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
:使用自定义比较器进行二分查找。线程安全的集合包装:
synchronizedList(List<T> list)
:返回一个线程安全的List
,基于指定的列表。synchronizedSet(Set<T> set)
:返回一个线程安全的Set
,基于指定的集合。synchronizedMap(Map<K,V> map)
:返回一个线程安全的Map
,基于指定的映射。这些静态工厂方法提供了方便的方式来创建和操作集合对象,简化了集合操作的代码实现。它们充分利用了 Java 泛型和静态方法的特性,提供了类型安全和易用性。
优点四:
静态工厂方法所返回对象的类可以输入的参数不同而改变:
在Java中,RegularEnumSet和JumboEnumSet是EnumSet的两个内部实现类。它们都是用于存储枚举类型元素的集合。
RegularEnumSet:
- RegularEnumSet是EnumSet的默认实现类。
- 它使用一个位向量(bit vector)来表示集合中的元素。
- 当枚举类型的元素数量较少时(通常在64个或更少),RegularEnumSet会被使用。
- RegularEnumSet的内部使用了long类型的数组,每个位表示一个枚举元素的存在与否。这种紧凑的表示形式使得RegularEnumSet在性能和内存消耗方面表现优异。
JumboEnumSet:
- 当枚举类型的元素数量超过64个时,EnumSet会使用JumboEnumSet作为其内部实现。
- JumboEnumSet使用一个BitSet来表示集合中的元素。
- BitSet是一个更大的位向量,它可以支持更多的枚举元素。
- JumboEnumSet以较高的内存消耗为代价,提供了对大型枚举集合的支持。
在大多数情况下,你不需要直接使用RegularEnumSet或JumboEnumSet,而是通过EnumSet的静态工厂方法来创建EnumSet对象。EnumSet会根据枚举类型的元素数量自动选择使用适当的内部实现类。
优点五:
静态工厂方法在编写包含该方法的类时,所返回对象的类并不一定存在:
在JDBC(Java数据库连接)中的服务提供者框架是一个典型的例子,其中静态工厂方法可以返回对象的类在编写包含该方法的类时并不一定存在。
在JDBC中,服务提供者框架用于加载和管理数据库驱动程序。驱动程序供应商可以通过实现特定接口并提供驱动程序的实现来注册其驱动程序。服务提供者框架允许应用程序通过静态工厂方法获取适当的驱动程序实例,而无需显式引用特定的驱动程序类。
下面是一个简化的示例,展示了JDBC服务提供者框架的代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class JDBCProviderFramework {// 私有构造函数,防止实例化private JDBCProviderFramework() {}// 静态工厂方法,返回数据库连接对象public static Connection getConnection(String url, String username, String password) throws SQLException {// 加载并注册合适的数据库驱动程序try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {throw new SQLException("Failed to load database driver");}// 获取数据库连接return DriverManager.getConnection(url, username, password);}
}public class Main {public static void main(String[] args) {String url = "jdbc:mysql://localhost:3306/mydb";String username = "root";String password = "password";try {Connection connection = JDBCProviderFramework.getConnection(url, username, password);// 使用数据库连接执行操作// ...} catch (SQLException e) {e.printStackTrace();}}
}
在上述示例中,JDBCProviderFramework
类是服务提供者框架的一部分。它包含一个私有构造函数和一个静态工厂方法 getConnection()
,用于获取数据库连接对象。
在 getConnection()
方法中,首先使用 Class.forName()
方法加载并注册合适的数据库驱动程序,这里以MySQL驱动程序为例。然后,通过 DriverManager.getConnection()
方法获取数据库连接对象,并将其返回。
在 Main
类的 main()
方法中,我们使用 JDBCProviderFramework.getConnection()
方法获取数据库连接对象,并在实际应用程序中使用该连接对象执行数据库操作。
这里的关键是,在编写 JDBCProviderFramework
类时,并没有显式引用或依赖于特定的数据库驱动程序类。相反,通过使用服务提供者框架和静态工厂方法,可以在未来动态加载和使用不同的数据库驱动程序,而无需修改 JDBCProviderFramework
类的代码。
这种设计允许在未来定义或扩展返回的对象类(即不同的数据库驱动程序),以适应新的数据库技术或供应商。通过配置和动态加载,应用程序可以灵活地选择和切换不同的数据库驱动程序,而不需要修改主要的代码逻辑。
这个例子展示了静态工厂方法在JDBC服务提供者框架中的应用,其中返回的对象的类在编写包含该方法的类时并不一定存在,而是根据具体的实现在运行时动态加载和使用。
这个太难理解了,感兴趣的读者可以去了解一下服务提供者框架!!
缺点一:
静态工厂方法因为没有共有的或者受保护的构造方法,就无法为这些类创建子类。(因祸得福)
静态工厂方法的一个特点是通过私有构造函数来限制实例化,因此没有公有或受保护的构造方法。这导致无法直接创建该类的子类,从而在一定程度上确保了类的封装性和不可继承性。
这种限制有时也可以被视为一种优势,因为它可以防止不必要或不合适的继承。静态工厂方法可以在类的实现中隐藏构造函数,将对象的创建控制权交给工厂方法,从而提供更精确的控制和灵活性。
尽管无法直接创建子类,但可以通过其他方式实现类似的扩展和定制。以下是一些常见的方法:
组合和委派:使用静态工厂方法返回的对象作为另一个类的成员,并将其方法暴露给外部使用。这样可以通过组合和委托的方式实现类似于继承的行为。
接口实现:通过实现接口,可以创建新的类并使用静态工厂方法返回的对象作为实现接口的一部分。这样可以扩展原始类的功能并定制行为。
静态工厂方法的参数化:静态工厂方法可以接受参数,并根据参数的不同返回不同的对象实例。通过合理设计参数,可以实现类似于子类化的效果。
虽然静态工厂方法限制了直接子类的创建,但可以通过以上方法实现类似的效果,并同时提供更好的灵活性和控制性。这种设计可以避免一些继承带来的问题,使代码更加清晰、可维护和可扩展。
缺点二:
在API文档中可能会很难发现这个方法。(无伤大雅)
静态工厂方法的命名方法没有固定的规范,但通常遵循一些常见的命名约定和惯例。以下是一些常见的命名方法:
of
或valueOf
:这是一种常见的命名模式,用于表示通过给定的参数创建对象实例。例如:of()
,valueOf()
,getInstance()
,create()
等。
from
:这种命名模式用于表示从给定的参数或源对象中创建对象实例。例如:from()
,fromX()
,fromXyz()
等。
newInstance
或newX
:这种命名模式用于表示创建新的对象实例。例如:newInstance()
,newX()
,newXyz()
等。
getX
:这种命名模式用于表示获取对象的实例,通常与工厂方法所创建的对象具有某种关联关系。例如:getX()
,getXyz()
,getXByY()
等。
createX
或buildX
:这种命名模式用于表示创建对象实例,通常与构建复杂对象或对象图相关。例如:createX()
,buildX()
,createXyz()
,buildXyz()
等。这些只是一些常见的命名方法示例,具体的命名方式可以根据项目的需求和团队的约定进行选择。重要的是选择一个能清晰表达方法意图和用途的命名,使代码易于阅读和理解。
此外,为了提高代码的可读性和一致性,建议在命名静态工厂方法时遵循一些通用的命名约定,例如使用驼峰命名法、使用具体和清晰的命名等。
相关文章:
用静态工厂方法代替构造器
用静态工厂方法来代替构造方法。 public class Student {private String name;private int age;private String studentId;private Student(String name, int age, String studentId) {this.name name;this.age age;this.studentId studentId;}public static Student creat…...

Discourse 最多允许有几个分类级别
和 DISCUZ 不同,DISCUZ 可以允许分类下面还有分类,再继续分类这种嵌套式分类。 Discourse 最多只允许有 2 个分类。 如果你在已有的分类下再继续分类的话,系统会提示错误: 意思就是子分类不能再分子分类。 Discourse 尽量采取了…...

MySQL数据库主从复制和读写分离
MySQL数据库主从复制和读写分离 。## MySQL主从复制 MySQL主从复制的概念 MySQL主从复制是一个异步的数据复制过程,允许将一个MySQL服务器(主服务器)上的数据复制到一个或多个MySQL服务器(从服务器)。主从复制提供了…...
rust - 使用log4rs打印日志
本文提供了一种通过log4rs库记录日志的方法。这里没有采用读取yaml文件的方式,而是通过对象构造的方式来初始化日志,用于发包时不带配置文件的场景。 初始化日志 在release环境,仅需要将日志打印到文件中,而日常开发时ÿ…...

数据结构:单调栈和单调队列
文章目录 一、单调栈1.1、栈的思想1.2、单调栈1.2.1、单调栈的基本应用:找出数组中每个元素右侧第一个更大的元素1.2.2、单调栈的基本应用:找出数组中每个元素左侧第一个更大的元素1.2.3、单调栈拓展1.2.4、单调栈LeetCode题单 二、单调队列2.1、队列的思…...
大模型RAG性能提升路径
大模型相关目录 大模型,包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步,扬帆起航。 大模型应用向开发路径:AI代理工作流大模型应用开发实用开源项目汇总大模…...
机器视觉学习(九)—— 边缘检测
目录 一、边缘检测 1.1 Canny边缘检测 1.1.1 cv2.Canny函数 1.1.2 Canny边缘检测示例 1.2 角点检测 1.2.1 cv2.goodFeaturesToTrack()函数 1.2.2 OpenCV角点检测示例代码 1.3 直线检测 1.3.1 cv2.HoughLinesP()函数 1.3.2 OpenCV直线检测示例代码 1.4 圆形检测 1.4…...

基于单片机声音分贝采集和显示控制系统设计
**单片机设计介绍,基于单片机声音分贝采集和显示控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机声音分贝采集和显示控制系统设计,主要目标是实现声音分贝的实时采集、处理以及显示…...

CentOS使用Docker部署Halo并结合内网穿透实现公网访问本地博客
文章目录 1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤:1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 本文主要介绍如何在CentOS 7系统使…...

打造高效自动化渗透测试系统:关键步骤与实践
随着当前网络安全威胁的不断扩展与升级,开展渗透测试工作已经成为广大企业组织主动识别安全漏洞与潜在风险的关键过程。然而,传统的人工渗透测试模式对测试人员的专业能力和经验水平有很高的要求,企业需要投入较大的时间和资源才能完成。在此…...

绿联 部署vocechat,搭建私人聊天服务器,用于小型团队和家庭环境
1、镜像 privoce/vocechat-server:latest 2、安装 2.1、基础设置 重启策略:容器退出时总是重启容器。 2.2、网络 桥接即可。 2.3、存储空间 装载路径:/home/vocechat-server/data不可变更,权限读写。 2.4、端口设置 容器端口3000不可变…...

考研数学|高效刷透汤家凤《1800》经验分享
当然不需要换老师,如果你在基础阶段连汤老师的课都听不进去,那么换其他老师的话,很大可能也是白搭。 如果你现在对于1800还是一筹莫展的话,那么很明显,这反映出前期基础不扎实,没有真正理解和掌握这部分内…...

LLM推理入门指南②:深入解析KV缓存
在本系列文章《LLM推理入门指南①:文本生成的初始化与解码阶段》中,作者对Transformer解码器的文本生成算法进行了高层次概述,着重介绍了两个阶段:单步初始化阶段,即提示的处理阶段,和逐个生成补全词元的多…...

上采样技术在语义分割中的应用
目录 概要 一、概述 二、实现方法 1.转置卷积 2.反池化 3.双线性插值法 三、在经典网络中的的应用 1.U-Net 2.FCN 总结 概要 上采样是用于深度学习中提高语义分割精度的技术,可以实现图像放大和像素级别标注 一、概述 神经网络的基本结构为:…...

linux 组建raid5详细操作
raid5最多运行损坏一个盘,最少3个盘,容量为少一块硬盘的容量之和。 如果硬盘数量较多,比如8块以上,建议用raid6,raid6最多允许两块硬盘损坏。 如果需要 一、安装raid软件 deb包 apt-get install mdadm或dnf包 dnf …...
机器学习概念、步骤、分类和实践
在当今数字化时代,机器学习已经渗透到我们生活的方方面面,从智能手机应用、搜索引擎优化,到自动驾驶汽车、医疗诊断等,其应用无处不在。本文将带您走进机器学习的世界,了解它的基本概念、步骤、分类以及实践应用。 一…...

钉钉服务端API报错 错误描述: robot 不存在;解决方案:请确认 robotCode 是否正确
problem 调用钉钉服务端API,机器人发送群聊消息,后台返回报错信息: 钉钉服务端API报错 错误描述: robot 不存在;解决方案:请确认 robotCode 是否正确; reason 定位: 登录后台,查看机器人是存在查看机器人调用权限接…...
Linux 开发环境以及编译链接
再谈编译链接 C函数重载与编译链接-CSDN博客 之前我已经写过文章简单介绍了编译链接要做的一些操作。现在为了能更好的理解我们平时的开发环境,我会在Linux系统上完整地走一遍流程。 环境描述 我们使用普通用户在Linux上进行操作,先写一段测试代码。 …...

SmartChart的部署以及可能遇见的报错解决方案
简介 数据可视化是一种将数据转化为图形的技术,可以帮助人们更好地理解和分析数据。但是,传统的数据可视化开发往往需要编写大量的代码,或者使用复杂的拖拽工具,不仅耗时耗力,而且难以实现个性化的需求。有没有一种更…...
【Node.js从基础到高级运用】十九、Node.js 捕获错误之“未捕获的异常”
引言 在 Node.js 应用程序中,错误处理是保证应用稳定性和可靠性的关键部分。特别是“未捕获的异常”(uncaught exceptions),如果不妥善处理,很可能会导致整个进程崩溃。在本文中,我们将探讨如何在 Node.js …...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...