写出优美的代码:考虑使用静态工厂方法替代构造方法

文章目录

  • 一、静态工厂方法区别于工厂方法模式
  • 二、静态工厂方法的优点
    • 1、有名字
      • (1)优势
      • (2)源码分析:BigInteger
      • (3)源码分析:Executors
      • (4)常用命名 名称
    • 2、不需要每次调用时都创建一个新对象
      • (1)优势
      • (2)源码分析:Boolean
    • 3、可以返回原返回类型的任何子类型
      • (1)优势
      • (2)源码分析:Collections
    • 4、返回对象的类可以根据输入参数的不同而不同
      • (1)优势
      • (2)源码分析:EnumSet
    • 5、编写包含该方法的类时,返回的对象的类不需要存在
  • 三、总结

一、静态工厂方法区别于工厂方法模式

本文的静态工厂方法与设计模式的工厂方法模式完全不同,要注意区分!

通常来说,我们创建一个类对象,直接使用new 调用其构造方法进行创建。但是静态工厂方法提供一个公共静态工厂方法,它是一个返回类实例的静态方法。

比如,获取一个People实例:

public static People getInstance() {return new People();
}

而不是通过调用构造方法获取People实例(此处只是举个静态工厂方法的例子,实际上有诸多用法)。

二、静态工厂方法的优点

1、有名字

(1)优势

区别于构造方法,静态工厂方法是有名字的,正因为它是一个方法,它可以给方法取任意的方法名。

有的类中构造方法有很多,如果不仔细描述构造方法中的参数含义,其创建的对象很难理解它们有什么不同的含义。
在一个类中需要具有相同签名的多个构造方法的情况下,用静态工厂方法替换构造方法,并仔细选择名称来突出它们的差异,创建对象时很容易就知道其方法的含义了。

(2)源码分析:BigInteger

BigInteger有众多的构造方法,单看这些构造方法,并不能很清晰的知道其具体的含义,需要翻遍注释慢慢去了解。

而使用静态工厂方法,可以根据其语义,很轻松知道该方法会返回一个什么对象。
在这里插入图片描述
例如BigInteger(int, int, Random)返回一个素数,但调用者很难理解API设计者所要想表达的意思,如果此时有BigInteger.probablePrime静态工厂方法,则能一目了然的清楚API设计者所要想表达的含义。

(3)源码分析:Executors

Java线程池ThreadPoolExecutor类共有七大参数,如果仅仅使用构造方法来创建线程池,恐怕对于一个新人程序员来说这是一个噩梦。

Executors类定义了newFixedThreadPool、newFixedThreadPool等等诸多静态工厂方法,使用寥寥几个参数就可以获取一个特定功能的线程池,因为它们有“名字”,并且做了一些封装与默认值,所有就较为清晰的明白API的含义。
在这里插入图片描述

(4)常用命名 名称

  • from——A 类型转换方法,它接受单个参数并返回此类型的相应实例,例如:Date d = Date.from(instant);
  • of——一个聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起,例如:Set faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf——from 和 to 更为详细的替代 方式,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance 或 getinstance——返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值,例如:StackWalker luke = StackWalker.getInstance(options);
  • create 或 newInstance——与 instance 或 getInstance 类似,除了该方法保证每个调用返回一个新的实例,例如:Object newArray = Array.newInstance(classObject, arrayLen);
  • getType——与 getInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:FileStore fs = Files.getFileStore(path);
  • newType——与 newInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型,例如:Buw eredReader br = Files.newBuw eredReader(path);
  • type—— getType 和 newType 简洁的替代方式,例如:List litany = Collections.list(legacyLitany);
  • 其他——根据方法的具体逻辑,简单描述方法的功能

2、不需要每次调用时都创建一个新对象

(1)优势

使用构造方法每次都会在内存中创建一个新对象,而静态工厂方法可以允许对象提前缓存或重用。

如果经常请求等价对象,或者某些对象创建时需要消耗极大的代价,它可以极大地提高性能。

这种技术常用于Flyweight(享元) 模式或者Singleton (单例)模式
设计模式之【享元模式】,共享单车火起来并不是没有原因的
设计模式之【单例模式】全解,单例模式实现方式,暴力打破单例模式与解决方案,你真的认识单例模式吗?

比如说一个最简单的饿汉式单例:

public class Instance() {private static Instance instance = new Instance();private Instance(){}public static Instance getInstance() {return instance;}
}

注意!静态工厂方法返回相同的对象,需要在任何时候保持对该对象实例的严格控制,这样做的类也叫实例控制( instance-controlled)。这也很好理解,因为如果该对象使用享元模式进行共享,修改了对象的属性及内容,所有引用该对象的地方都会感知到这一事件。

(2)源码分析:Boolean

Boolean的valueOf方法就是基于这种思想,提前将True和False进行缓存,每次获取的都是相同的实例,这避免了每次通过构造方法创建新的对象,极大的提高了性能。

同时,其构造方法,在jdk9就已经弃用了。

public static final Boolean TRUE = new Boolean(true);public static final Boolean FALSE = new Boolean(false);@IntrinsicCandidate
public static Boolean valueOf(boolean b) {return (b ? TRUE : FALSE);
}@Deprecated(since="9", forRemoval = true)
public Boolean(boolean value) {this.value = value;
}

3、可以返回原返回类型的任何子类型

(1)优势

这种方式在选择返回对象的类时提供了很大的灵活性。这种技术适用于基于接口的框架,其中接口为静态工厂方法提供自然返回类型。

比如说Collections工具类,List list = Collections.synchronizedList(new ArrayList()) ,这与装饰者模式非常像:
设计模式之【装饰者模式】,实现“穿衣打扮”自由原来这么简单

(2)源码分析:Collections

Collections工具类中提供了大量的包装类。
在这里插入图片描述
比如说,synchronizedList,将传入的参数进行包装,将所有的方法都加上synchronized确保线程安全,这相当于装饰者模式的一种落地实现:
在这里插入图片描述
在这里插入图片描述

4、返回对象的类可以根据输入参数的不同而不同

(1)优势

这个优点与上一个优点类似,返回的类动态变化,一定是需要继承与本类或者实现了与本类相同的接口。

(2)源码分析:EnumSet

EnumSet的noneOf它们根据底层枚举类型的大小返回两个子类中的一个的实例:如果大多数枚举类型具有 64 个或更少的元素,静态工厂将返回一个RegularEnumSet 实例, 返回一个 long 类型;如果枚举类型具有六十五个或更多元素,则工厂将返回一个JumboEnumSet 实例,返回一个 long 类型的数组。

这两个实现类的存在对于客户是不可见的。 如果 RegularEnumSet 不再为小枚举类型提供性能优势,则可以在未来版本中将其淘汰,而不会产生任何不良影响。 同样,未来的版本可能会添加 EnumSet 的第三个或第四个实现,如果它证明有利于性能。 客户既不知道也不关心他们从工厂返回的对象的类别; 他们只关心它是 EnumSet 的一些子类。
在这里插入图片描述

5、编写包含该方法的类时,返回的对象的类不需要存在

这种灵活的静态工厂方法构成了服务提供者框架的基础,比如 Java 数据库连接 API(JDBC)。服务提供者框架是提供者实现服务的系统,并且系统使得实现对客户端可用,从而将客户端从实现中分离出来。

例如DriverManager.getConnection,获取的连接mysql、oracle是根据Driver驱动进行动态连接的。JDK只提供了DriverManager进行jdbc管理,而客户端需要各大厂商自行实现,实现了客户端与服务提供者进行分离。

同理,slf4j日志门面也是如此,门面和具体的实现分离,各自进行维护。

这也类似于门面模式的一种落地。

三、总结

虽然静态工厂方法有诸多优点,但是要结合实际应用场景。

如果只有静态工厂方法而没有公共或受保护构造方法,这将导致该类无法提供子类。例如,在 Collections框架中不可能将任何方便实现类子类化。可以说,这可能是因祸得福,因为它鼓励程序员使用组合而不是继承,并且是不可变类型(final)。

另外,静态工厂方法在API文档上,和普通静态方法混杂在一起,因此要想区分静态工厂方法和普通静态方法,或许要花费一定的精力。所以,静态工厂方法的命名很有讲究(参考本文静态工厂方法的命名)。

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

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

相关文章

苹果cms论坛多播放源自动采集在线影视网站

苹果 cms 论坛一个基于 vue 和 gin 实现的在线观影网站 项目采用 vite vue 作为前端技术栈, 使用 ElementPlus 作为 UI 框架进行开发 后端程序使用 Gin gorm go-redis 等相关框架提供接口服务, 使用 gocolly 和 robfig/cron 进行公共影视资源采集和定时更新功能 目前用户…

目前比较好用的护眼台灯?最好用的五款护眼台灯推荐

灯具可以说是我们日常生活中使用很频繁的工具了,我们每天都离不开它给我们带来的光亮。当然,现在灯具也有很多种类可以挑选,今天主要带来五款非常好用的护眼台灯指南。 1.书客护眼台灯Pro 使用体验分数:10分 亮点:具…

笔记:IDEA如何修改代码后,不重启服务器局部更新资源

前言 平常用IDEA开发网页写调样式和测功能最讨厌改一丁点东西就要重启整个服务器,所以本文主要就是解决此问题从而提高开发效率,避免浪费过多时间。 具体步骤 1、打开设置框 2、先新增exploded结尾的,并apply应用,把没有结尾的…

ch0_OSI 七层网络协议介绍

目录 概述 1、三网融合的概念 三网:电信网络、有线电视网络、计算机网络 概念:把上述三种网络融合成一种网络 2、计算机网络的定义、分类 定义:计算机网络是将地理位置不同的独立计算机系统,通过传输介质链接起来&#xff0c…

HTML样式CSS、图像

HTML样式-CSS: CSS (Cascading Style Sheets) 用于渲染HTML元素标签的样式。CSS可以通过以下方式添加到HTML中&#xff1a;1&#xff09;、内联方式&#xff1a;在HTML元素中使用“style”属性&#xff1b;2&#xff09;、内部样式表&#xff1a;在HTML文档头部<head>区…

阿里云OS系统Alibaba Cloud Linux 3系统的安全更新命令

给客户部署的服务&#xff0c;进入运维阶段&#xff0c;但是经常被客户监测到服务器漏洞&#xff0c;现在整理一下&#xff0c;服务器漏洞问题更新命令步骤。 服务器系统&#xff1a; 阿里云linux服务器&#xff1a;Alibaba Cloud Linux 3 漏洞类型和描述&#xff1a; #3214…

微课录屏软件哪个好?帮你轻松搞定课程录制

微课作为一种新型的教学方式&#xff0c;因其短小精悍、内容丰富等特点&#xff0c;越来越受到广大师生的喜爱。在制作微课时&#xff0c;选择一款合适的录屏软件显得尤为重要。可是微课录屏软件哪个好呢&#xff1f;本文将详细介绍两款微课录屏软件&#xff0c;并进行全方位对…

STM32-HAL库08-TIM的输出比较模式(输出PWM的另一种方式)

STM32-HAL库08-TIM的输出比较模式&#xff08;输出PWM的另一种方式&#xff09; 一、所用材料&#xff1a; STM32F103C6T6最小系统板 STM32CUBEMX&#xff08;HAL库软件&#xff09; MDK5 示波器或者逻辑分析仪 二、所学内容&#xff1a; 通过定时器TIM的输出比较模式得到预…

C++初阶(七)类和对象

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、流插入流提取1、流插入演示2、流提取演示3、cplusplus推荐 二、const成员三、取地址及con…

Go 如何实现并发

Go语言的并发机制是其强大和流行的一个关键特性之一。Go使用协程&#xff08;goroutines&#xff09;和通道&#xff08;channels&#xff09;来实现并发编程&#xff0c;这使得编写高效且可维护的并发代码变得相对容易。下面是Go的并发机制的详细介绍&#xff1a; 协程&#x…

指纹识别之dns

https://ephen.me/2017/dns-tcp/ https://c.biancheng.net/view/6457.html https://www.jianshu.com/p/b483300378af https://www.cnblogs.com/549294286/p/5172448.html wireshark数据包分析 Packet Details Pane(数据包详细信息), 在数据包列表中选择指定数据包&#xff0c;…

循环神经网络 - RNN

循环神经网络&#xff08;Rerrent Neural Network,RNN&#xff09;是神经网络的一种&#xff0c;类似的还有深度神经网络&#xff08;DNN&#xff09;、卷积神经网路(CNN)、生成对抗网络&#xff08;GAN)等。**RNN对具有时序特性的数据非常有成效&#xff0c;他能挖掘数据中的时…

Asterisk Ubuntu 安装

更新环境 sudo apt update sudo apt install wget build-essential git autoconf subversion pkg-config libtool sudo contrib/scripts/get_mp3_source.sh A addons/mp3 A addons/mp3/common.c A addons/mp3/huffman.h A addons/mp3/tabinit.c A addons/mp3/Ma…

【Midjourney入门教程2】Midjourney的基础操作和设置

文章目录 Midjourney的常用命令和基础设置1、 /imagine2、 /blend3、 /info4、 /subscribe5、 /settings&#xff08;Midjourney的基础设置&#xff09;6、 /shorten 有部分同学说我不想要英文界面的&#xff0c;不要慌&#xff1a; 点击左下角个人信息的设置按钮&#xff0c;找…

Vue分页控件报错 “pagerCount“

报错信息&#xff1a;[Vue warn]: Invalid prop: custom validator check failed for prop “pagerCount”. <template><div class"pagination"><el-paginationsmallbackground:layout"layout":total"total":current-page"…

深度学习之基于ResNet18的神经网络水果分类系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介二、功能三、神经网络水果分类系统四. 总结 一项目简介 基于ResNet18神经网络的水果分类系统是一个利用深度学习技术进行水果图像分类的系统。下面是该系统…

Web APIs——节点操作

1、DOM节点 DOM节点&#xff1a;DOM树里每一个内容都称之为节点 节点类型&#xff1a; 元素节点 所有的标签 比如body、div属性节点 所有的属性 比如 href文本节点 所有的文本其他 2、查找节点 关闭二维码案例&#xff1a; 点击关闭按钮&#xff0c;关闭的是二维码的盒子&#…

第02章_MySQL环境搭建

第02章_MySQL环境搭建 讲师&#xff1a;尚硅谷 宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 1. MySQL的卸载 步骤1&#xff1a;停止MySQL服务 在卸载之前&#xff0c;先停止MySQL8.0的服务。按键盘上的“Ctrl Alt …

https原理

首先说一下几个概念&#xff1a;对称加密、非对称加密 对称加密&#xff1a; 客户端和服务端使用同一个秘钥&#xff0c;分两种情况&#xff1a; 1、所有的客户端和服务端使用同一个秘钥&#xff0c;这个秘钥被泄漏后数据不再安全 2、每个客户端生成一个秘钥&…