用静态工厂方法代替构造器

用静态工厂方法来代替构造方法。

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 方法...}

静态工厂方法相较于构造方法的五个优点:

  1. 有自己的名称,而构造方法必须与类名一致。
  2. 不用每次被调用时都会创建一个新的对象,它可以返回预先构造好的对象。
  3. 可以返回所声明的返回类型的任何子类型的对象。
  4. 所返回对象的类可以输入的参数不同而改变。
  5. 在编写包含该方法的类时,所返回对象的类并不一定存在。

缺点:

  1. 如果没有共有的或者受保护的构造方法,就无法为这些类创建子类。(因祸得福)
  2. 在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)是一种创建型设计模式,旨在确保类只有一个实例,并提供全局访问点以访问该实例。

单例模式的主要特点是:

  1. 保证类只有一个实例:通过限制类的实例化过程,确保在程序运行期间只存在一个实例对象。
  2. 全局访问点:提供一个全局的访问方法,使其他对象可以方便地获取该单例实例。

使用单例模式的主要优点包括:

  1. 对资源的集中管理:单例模式可以集中管理某些共享的资源,确保资源的一致性和可靠性。
  2. 节约系统资源:由于只有一个实例存在,可以减少系统开销,节约内存和处理器等资源。
  3. 简化对象之间的通信:通过单例对象,可以简化对象之间的通信,避免了传递多个对象引用的复杂性。

常见的单例模式实现方式有两种:它们的区别在于对象的创建时间点不同。

  1. 饿汉模式(Eager Initialization):

    • 在类加载时就创建并初始化单例对象。
    • 对象在整个生命周期中都存在,无论是否被使用。
    • 线程安全,不需要考虑多线程环境。
    • 简单直接,但可能导致资源浪费。
  2. 懒汉模式(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 类中常用的静态工厂方法:

  1. 创建不可修改的集合(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,基于指定的映射。
  2. 集合的排序和查找:

    • 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):使用自定义比较器进行二分查找。
  3. 线程安全的集合包装:

    • 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文档中可能会很难发现这个方法。(无伤大雅)

静态工厂方法的命名方法没有固定的规范,但通常遵循一些常见的命名约定和惯例。以下是一些常见的命名方法:

  1. of 或 valueOf:这是一种常见的命名模式,用于表示通过给定的参数创建对象实例。例如:of()valueOf()getInstance()create()等。

  2. from:这种命名模式用于表示从给定的参数或源对象中创建对象实例。例如:from()fromX()fromXyz()等。

  3. newInstance 或 newX:这种命名模式用于表示创建新的对象实例。例如:newInstance()newX()newXyz()等。

  4. getX:这种命名模式用于表示获取对象的实例,通常与工厂方法所创建的对象具有某种关联关系。例如:getX()getXyz()getXByY()等。

  5. createX 或 buildX:这种命名模式用于表示创建对象实例,通常与构建复杂对象或对象图相关。例如:createX()buildX()createXyz()buildXyz()等。

这些只是一些常见的命名方法示例,具体的命名方式可以根据项目的需求和团队的约定进行选择。重要的是选择一个能清晰表达方法意图和用途的命名,使代码易于阅读和理解。

此外,为了提高代码的可读性和一致性,建议在命名静态工厂方法时遵循一些通用的命名约定,例如使用驼峰命名法、使用具体和清晰的命名等。

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

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

相关文章

windows安装Chocolatey

其实官网就有介绍&#xff0c;贴上原址&#xff1a; Chocolatey Software | Installing Chocolatey 安装步骤&#xff1a; 1、winX选择Windows Powershell(管理员) 2、复制以下指令 Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]:…

接口自动化框架搭建(九):接入钉钉消息通知

1&#xff0c;jenkins安装钉钉插件 2&#xff0c;在钉钉群聊设置机器人 3&#xff0c;jenkins配置钉钉 根据情况选择&#xff1a; 除了这些&#xff0c;其他不用配置&#xff0c;配置完成点击确认 4&#xff0c;项目配置 添加后保存 5&#xff0c;测试下效果 构建完成后&a…

一文教你如何轻松领取腾讯云优惠券

腾讯云作为国内领先的云计算服务商&#xff0c;为用户提供了丰富的云产品和服务。为了让更多用户享受到腾讯云服务的优质体验&#xff0c;腾讯云推出了各种优惠券&#xff0c;让用户在购买云服务时能够获得更多实惠。本文将为大家详细介绍如何轻松领取腾讯云优惠券&#xff0c;…

从供方协议管理到外部供方管理

从GJB 5000A的供方协议管理到GJB 5000B的外部供方管理&#xff0c;军用软件的研制对承接单位有了更高的标准和要求&#xff0c;也对外部供方管理有了更改的要求&#xff0c;让我们看看具体的变化吧&#xff01; 供方协议管理的目的&#xff1a; 管理供方产品的获取工作。 外部…

FL Studio21.2.3中文版音乐制作编曲软件功能展示讲解

FL Studio 21&#xff0c;确实被广大音乐制作人亲切地称为“水果”。这款软件以其强大的功能和用户友好的界面在音乐制作领域占据了重要地位。 FL Studio 21&#xff08;水果&#xff09;是一款全能的音乐创作软件&#xff0c;也是一款强大的编曲软件&#xff0c;可以作为编曲…

小蜜蜂老师的【基础技能15】综合实训案例代码

该代码是自己写的&#xff0c;没有参考老师的代码&#xff0c;仅供参考&#xff0c;如有不合适请指出&#xff0c;谢谢。 #include "reg52.h"sfr AUXR0x8e;sbit S5P3^2; sbit S4P3^3;void SelectHC573(unsigned char channel); void DisplayTime(); unsigned char …

【Linux】体验一款开源的Linux服务器运维管理工具

今天为大家介绍一款开源的 Linux 服务器运维管理工具 - 1panel。 一、安装 根据官方那个提供的在线文档&#xff0c;这款工具的安装需要执行在线安装&#xff0c; # Redhat / CentOScurl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start…

代码随想录算法训练营DAY11|C++栈和队列Part.2|LeetCode:20.有效的括号、 1047.删除字符串中所有相邻重复项、150.逆波兰表达式

文章目录 20.有效的括号思路CPP代码 1047.删除字符串中所有相邻重复项思路CPP代码 150.逆波兰表达式思路什么是逆波兰表达式本题的思路 CPP代码 20.有效的括号 力扣题目链接 文章链接&#xff1a;20.有效的括号 视频链接&#xff1a;LeetCode&#xff1a;20. 有效的括号 状态&a…

你在测试金字塔的哪一层(下)

​在《你在测试金字塔的哪一层&#xff08;上&#xff09;》中介绍了自动化测试的重要性以及测试金字塔。测试金字塔分为单元测试、服务测试、UI测试&#xff0c;它们分别是什么呢&#xff1f;本期文章让我们一起详细看看测试金字塔的不同层次。 一、单元测试 单元测试是指对程…

web使其盒子向里面倾斜

右侧向内倾斜 transform: perspective(500px) rotateX(0deg) rotateY(-10deg) rotateZ(0deg);transform-origin: 270px 424px;效果 左侧向内倾斜 transform: perspective(500px) rotateX(0deg) rotateY(10deg) rotateZ(0deg);transform-origin: 270px 424px;效果

Conda 命令

1.更新 #获取版本号 conda --version 或 conda -V conda update conda # 基本升级 conda update anaconda # 大的升级 conda update anaconda-navigator #update最新版本的anaconda-navigator 2.卸载 Anaconda的安装文件都包含在一个目录中&#xff0c;直…

蓝桥杯小白月赛第八场第三题

题目描述&#xff1a; 思路&#xff1a; 根据上面的次方数&#xff0c;我们可以看出来从1次方到4次方 和 5 - 8次方&#xff0c;中间有什么规律&#xff1f; 是不是可以看出来1次方和5次方的尾数相同 2次方和6次方的尾数相同 3次方和7次方的尾数相同 4次方和8次方的尾数相同 …

ctf.show_web11

<?php function replaceSpecialChar($strParam){ $regex "/(select|from|where|join|sleep|and|\s|union|,)/i"; return preg_replace($regex,"",$strParam); } // \s 空格 if(strlen($password)!…

2024年N1叉车司机证考试题库及N1叉车司机试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年N1叉车司机证考试题库及N1叉车司机试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机出的…

Kaggle注册验证码问题(Captcha must be filled out.)

Kaggle注册验证码问题 Captcha must be filled out.使用Edge浏览器 Header Editor 插件安装 下载插件Header Editor 导入重定向脚本 点击扩展插件&#xff0c; 打开Header Editor插件&#xff0c;进行管理 点击导入输入下载链接进行下载或者导入本地json文件(二者任选其一…

QT 最近使用的项目配置文件

目录 1 QT 最近使用的项目配置文件所在路径 2 QtCreator.ini 1 QT 最近使用的项目配置文件所在路径 C:\Users\your username\AppData\Roaming\QtProject QtCreator.ini最好先备份一份 2 QtCreator.ini ProjectExplorer 下面的 RecentProjects\FileNames RecentProjects\…

ThreadPool-线程池使用及原理

1. 线程池使用方式 示例代码&#xff1a; // 一池N线程 Executors.newFixedThreadPool(int) // 一个任务一个任务执行&#xff0c;一池一线程 Executors.newSingleThreadExecutorO // 线程池根据需求创建线程&#xff0c;可扩容&#xff0c;遇强则强 Executors.newCachedThre…

php数组算法(2)字符串转数组后替换指定元素

php中&#xff0c;如何替换字符串“name1,name2,name3”中的name2&#xff0c;输出“name1,name3”格式? 完整代码 $str "name1,name2,name3"; $search "name2"; echo replaceString($str, $search);/** param $str&#xff0c;字符串格式:name1,name2…

C++:继承的介绍和深度解析

一、继承的概念和定义 1.什么是继承&#xff1f; 继承&#xff0c;顾名思义&#xff1a;就和现实生活中&#xff0c;孩子继承父母的东西有点类似。比如&#xff0c;你父亲的财产&#xff0c;你可以继承下来&#xff0c;你就可以使用父亲的钱。 官方一点的介绍&#xff1a; 继承…

JUC/多线程 模式(四)

一、同步模式之保护性暂停 即 Guarded Suspension &#xff0c;用在一个线程等待另一个线程的执行结果 产生结果的线程和使用结果的线程是一一对应的&#xff0c;有多少个生产结果的线程就有多少个使用结果的线程。 要点 有一个结果需要从一个线程传递到另一个线程&#xff0…