设计模式-15-Jdk源码中的设计模式
之前我们学习了一些设计模式,今天我们剖析Java JDK 源码中用到的几种常见的设计模式。
1-jdk之工厂模式
在前面讲到工厂模式的时候,大部分工厂类都是以Factory作为后缀来命名,并且工厂类主要负责创建对象这样一件事情。但在实际的项目开发中,工厂类的设计更加灵活。那我们就来看下,工厂模式在Java JDK中的一个应用:java.util.Calendar。
public static Calendar getInstance(){return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}private static Calendar createCalendar(TimeZone zone,Locale aLocale){CalendarProvider provider =LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider();if (provider != null) {try {return provider.getInstance(zone, aLocale);} catch (IllegalArgumentException iae) {// fall back to the default instantiation}}Calendar cal = null;if (aLocale.hasExtensions()) {String caltype = aLocale.getUnicodeLocaleType("ca");if (caltype != null) {switch (caltype) {case "buddhist":cal = new BuddhistCalendar(zone, aLocale);break;case "japanese":cal = new JapaneseImperialCalendar(zone, aLocale);break;case "gregory":cal = new GregorianCalendar(zone, aLocale);break;}}}if (cal == null) {if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {cal = new BuddhistCalendar(zone, aLocale);} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"&& aLocale.getCountry() == "JP") {cal = new JapaneseImperialCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}}return cal;}
getInstance()方法可以根据不同TimeZone和Locale,创建不同的Calendar子类对象,比如BuddhistCalendar、JapaneseImperialCalendar、GregorianCalendar,这些细节完全封装在工厂方法createCalendar中,使用者只需要传递当前的时区和地址,就能够获得一个Calendar类对象来使用,而获得的对象具体是哪个Calendar子类的对象,使用者在使用的时候并不关心。
2-jdk之建造者模式
建造者模式有两种实现方法,一种是单独定义一个Builder类,另一种是将Builder实现为原始类的内部类。Calendar就采用了第二种实现思路。
public static class Builder {private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEARprivate static final int WEEK_YEAR = FIELD_COUNT;private long instant;//省略其他的成员变量}
在Builder里面还有build方法来创建Calendar类对象;既然已经有了getInstance()工厂方法来创建Calendar类对象,为什么还要用Builder来创建Calendar类对象呢?这两者之间的区别在哪里呢?工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象。
粗看Calendar的Builder类的build()方法,你可能会觉得它有点像工厂模式。你的感觉没错,前面一半代码确实跟getInstance()工厂方法类似,根据不同的type创建了不同的Calendar子类。实际上,后面一半代码才属于标准的建造者模式,根据setXXX()方法设置的参数,来定制化刚刚创建的Calendar子类对象。
3-jdk之装饰器模式
Java IO类库是装饰器模式的非常经典的应用。实际上,Java的Collections类也用到了装饰器模式。Collections类是一个集合容器的工具类,提供了很多静态方法,用来创建各种集合容器,比如通过unmodifiableColletion()静态方法,来创建UnmodifiableCollection类对象。而这些容器类中的UnmodifiableCollection类、CheckedCollection和SynchronizedCollection类,就是针对Collection类的装饰器类。
装饰器模式中的装饰器类是对原始类功能的增强。UnmodifiableCollection的构造函数接收一个Collection类对象,然后对其所有的函数进行了包裹(Wrap):重新实现(比如add()函数)或者简单封装(比如stream()函数)。而简单的接口实现或者继承,并不会如此来实现UnmodifiableCollection类。所以,从代码实现的角度来说,UnmodifiableCollection类是典型的装饰器类。
4-jdk之适配器模式
老版本的JDK提供了Enumeration类来遍历容器。新版本的JDK用Iterator类替代Enumeration类来遍历容器。为了兼容老的客户端代码(使用老版本JDK的代码),我们保留了Enumeration类,并且在Collections类中,仍然保留了enumaration()静态方法(因为我们一般都是通过这个静态函数来创建一个容器的Enumeration类对象)。
在新版本的JDK中,Enumeration类是适配器类。它适配的是客户端代码(使用Enumeration类)和新版本JDK中新的迭代器Iterator类。不过,从代码实现的角度来说,这个适配器模式的代码实现,跟经典的适配器模式的代码实现,差别稍微有点大。enumeration()静态函数的逻辑和Enumeration适配器类的代码耦合在一起,enumeration()静态函数直接通过new的方式创建了匿名类对象。
public static <T> Enumeration<T> enumeration(final Collection<T> c) {return new Enumeration<T>() {private final Iterator<T> i = c.iterator();public boolean hasMoreElements() {return i.hasNext();}public T nextElement() {return i.next();}};
}
5-jdk之模板模式
Java中的Collections类的sort()函数就是利用了模板模式的这个扩展特性。Collections.sort()实现了对集合的排序。为了扩展性,它将其中“比较大小”这部分逻辑,委派给用户来实现。如果我们把比较大小这部分逻辑看作整个排序逻辑的其中一个步骤,那我们就可以把它看作模板模式。不过,从代码实现的角度来看,它看起来有点类似之前讲过的JdbcTemplate,并不是模板模式的经典代码实现,而是基于Callback回调机制来实现的。
6-jdk之观察者模式
之前我们讲解观察者模式的时候说到Google Guava的EventBus框架,它提供了观察者模式的骨架代码,使用EventBus。Java JDK也提供了观察者模式的简单框架实现。只包含两个类:java.util.Observable和java.util.Observer。前者是被观察者,后者是观察者。
7-jdk之单例模式
JDK中java.lang.Runtime类就是一个单例类。每个Java应用在运行时会启动一个JVM进程,每个JVM进程都只对应一个Runtime实例,用于查看JVM状态以及控制JVM行为。进程内唯一,所以比较适合设计为单例。在编程的时候,我们不能自己去实例化一个Runtime对象,只能通过getRuntime()静态方法来获得。它使用了最简单的饿汉式的单例实现方式。
public class Runtime {private static Runtime currentRuntime = new Runtime();public static Runtime getRuntime() {return currentRuntime;}/** Don't let anyone else instantiate this class */private Runtime() {}//....public void addShutdownHook(Thread hook) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("shutdownHooks"));}ApplicationShutdownHooks.add(hook);}//.
8-jdk之其他模式
享元模式,Integer类中的-128~127之间的整型对象是可以复用的,还讲到String类型中的常量字符串也是可以复用的。这些都是享元模式的经典应用。
职责链模式,Java Servlet中的Filter就是通过职责链来实现的,同时还对比了Spring中的interceptor。实际上,拦截器、过滤器这些功能绝大部分都是采用职责链模式来实现的。
迭代器模式,重点剖析了Java中Iterator迭代器的实现。
相关文章:
设计模式-15-Jdk源码中的设计模式
之前我们学习了一些设计模式,今天我们剖析Java JDK 源码中用到的几种常见的设计模式。 1-jdk之工厂模式 在前面讲到工厂模式的时候,大部分工厂类都是以Factory作为后缀来命名,并且工厂类主要负责创建对象这样一件事情。但在实际的项目开发中…...

Vue框架学习笔记——事件scroll和wheel的区别
文章目录 前文提要滚动条滚动事件 scroll鼠标滚动事件 wheel二者不同点 前文提要 本人仅做个人学习记录,如有错误,请多包涵 滚动条滚动事件 scroll scroll事件绑定html页面中的指定滚动条,无论你拖拽滚动条,选中滚动条之后按键盘…...

【LeetCode】每日一题 2023_11_29 无限集中的最小数字(哈希/堆)
文章目录 刷题前唠嗑题目:无限集中的最小数字题目描述代码与解题思路偷看大佬题解 结语 刷题前唠嗑 LeetCode?启动!!! 今天的题目也比较的简单,因为数据量不大,所以什么做法都能过的去 题目&a…...
C/C++ 常用的四种查找算法
在计算机科学中,搜索算法是一种用于在数据集合中查找特定元素的算法。C语言作为一种强大的编程语言,提供了多种搜索算法的实现方式。本文将介绍C语言中的四种常见搜索算法其中包括(线性查找,二分法查找,树结构查找&…...

Linux | Ubuntu设置 netstat(网络状态)
netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告。 1.netstat的安装 搜…...

成为AI产品经理——模型构建流程(下)
目录 1.模型训练 2.模型验证 3.模型融合 4.模型部署 上节课我们讲了模型设计、特征工程,这节课我们来讲模型构建剩下的三个部分:模型训练、模型验证和模型融合。 1.模型训练 模型训练就是要不断地训练、验证、调优直至让模型达到最优。 那么怎么达…...
TCP Socket API 讲解,以及回显服务器客户端的实现
文章目录 TCPServerSocket APISocket API TCP 客户端服务器的实现 TCP ServerSocket API ServerSocket 是创建TCP服务端 Socket 的 API。 serverSocket构造方法: 方法签名方法说明ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端…...

2023年掌控安全学院CTF暖冬杯——数据流分析
前言:打工仔一枚,第一波上新的3题misc 做完了 再打ISCTF随便记录一下 PS:环境关了,题目描述忘记了,反正就是找flag。 筛选HTTP数据流 导出数据流慢慢看 ctrl F 搜flag 看到一条 有flag.txt 的数据 导出另存.zip 这里…...

UE4 基础篇十四:自定义插件
文末有视频地址和git地址 一、概念 虚幻里插件都是用C++写的,C++包括.h文件和.cpp文件,.h头文件通常包含函数类型和函数声明,cpp文件包含这些类型和函数的实现, 你为项目编写的所有代码文件都必须位于模块中,模块就是硬盘里的一个文件夹,包含名为“Build.cs”的C#文件…...

QT QGraphicsItem 图元覆盖导致鼠标点击事件不能传递到被覆盖图元
一、概述 在日常开发中,遇到这样一个问题,线图元和引脚图元重叠,导致点击引脚图元,没有进入引脚图元的鼠标点击事件中。 二、产生原因 如果您的 QGraphicsItem 上有一个图元覆盖了它,可能会导致鼠标事件无法正常触发…...
proto语法学习笔记
proto语法学习笔记 Protocol Buffers(Proto是由谷歌开发的一种数据序列化格式。 Proto 不是一种编程语言,而是一种接口描述语言(IDL),用于定义数据结构和消息格式。 它的设计目标是提供一种简单、高效、可扩展的方法来…...

python-nmap库使用教程(Nmap网络扫描器的Python接口)(功能:主机发现、端口扫描、操作系统识别等)
文章目录 Python-nmap库使用教程前置条件引入python-nmap创建Nmap扫描实例执行简单的主机发现(nmap -sn)示例,我有一台主机配置为不响应 ICMP 请求,但使用nmap -sn,仍然能够探测到设备: 端口扫描扫描特定端…...

什么是智慧工地?
一、什么是智慧工地? 工地本身不拥有智慧,工地的运作是依赖于人的智慧。工地信息化技术,能够减少对人的依赖,使工地拥有智慧。 智慧工地,就是立足于“智慧城市”和“互联网”,采用云计算、大数据和物联网等…...

【古月居《ros入门21讲》学习笔记】08_发布者Publisher的编程实现
目录 说明: 1. 话题模型 图示 说明 2. 实现过程(C) 创建功能包 创建发布者代码(C) 配置发布者代码编译规则 编译并运行 编译 运行 3. 实现过程(Python) 创建发布者代码(…...

沿着马可·波罗的足迹,看数字云南
刚入行的时候,有位前辈跟我说过一句话:去现场“要像外国人一样去看”,重新审视那些自己可能早已“熟视无睹”的事物。 前不久,我跟随“看见数字云南——云南数字经济媒体探营活动”,奔赴昆明、大理、西双版纳等地&…...
记录问题-使用@Validated报错Validation failed for argument [0]
类字段 NotNull(message "双坐标不能为空", groups {Insert.class, Update.class})private Integer yAxisType;接口 /*** 添加** return*/RequestMapping(value "/add", method RequestMethod.POST)public Result add(Validated(Insert.class) Request…...

three.js--立方体
作者:baekpcyyy🐟 使用three.js渲染出可以调节大小的立方体 1.搭建开发环境 1.首先新建文件夹用vsc打开项目终端 2.执行npm init -y 创建配置文件夹 3.执行npm i three0.152 安装three.js依赖 4.执行npm I vite -D 安装 Vite 作为开发依赖 5.根…...

App的测试,和传统软件测试有哪些区别?应该增加哪些方面的测试用例?
从上图可知,测试人员所测项目占比中,App测试占比是最高的。 这就意味着学习期间,我们要花最多的精力去学App的各类测试。也意味着我们找工作前,就得知道,App的测试点是什么,App功能我们得会测试࿰…...

改进LiteOS中物理内存分配算法(详细实验步骤+相关源码解读)
一、实验要求 优化TLSF算法,将Best-fit策略优化为Good-fit策略,进一步降低时间复杂度至O(1)。 优化思路: 1.初始化时预先为每个索引中的内存块挂上若干空闲块,在实际分配时避免分割(split)操作ÿ…...

洛谷100题DAY8
36.P1416 攻击火星 此题找出规律即可 #include<bits/stdc.h> using namespace std; int n; int main() {cin >> n;cout << max(0, n - 2);return 0; } 37.P1551 亲戚 并查集模板题目 两个人如果使亲戚就合并建立联系,最后进行查找即可 #incl…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...