【开源与项目实战:开源实战】81 | 开源实战三(上):借Google Guava学习发现和开发通用功能模块

news2025/1/10 20:40:12

上几节课,我们拿 Unix 这个超级大型开源软件的开发作为引子,从代码设计编写和研发管理两个角度,讲了如何应对大型复杂项目的开发。接下来,我们再讲一下 Google 开源的 Java 开发库 Google Guava。

Google Guava 是一个非常成功、非常受欢迎的开源项目。它在 GitHub 上由近 3.7 万的 stars。在 Java 项目开发中应用很广泛。当然,我们并不会讲解其中的每个类、接口如何使用,而是重点讲解其背后蕴含的设计思想、使用的设计模式。内容比较多,我分三节课来讲解。

  • 第一节课,我们对 Google Guava 做一个简单介绍,并借此讲一下如何开发一个通用的功能模块。

  • 第二节课,我们讲 Google Guava 中用到的几种设计模式,会补充讲解之前没有讲到的 Immutable 模式。

  • 第三节课,我们借 Google Guava 补充讲解三大编程范式中的最后一个:函数式编程。

话不多说,让我们正式开始今天的学习吧!

Google Guava 介绍

考虑到你可能不熟悉 Google Guava,我先对它做下简单的介绍。

Google Guava 是 Google 公司内部 Java 开发工具库的开源版本。Google 内部的很多 Java 项目都在使用它。它提供了一些 JDK 没有提供的功能,以及对 JDK 已有功能的增强功能。其中就包括:集合(Collections)、缓存(Caching)、原生类型支持(Primitives Support)、并发库(Concurrency Libraries)、通用注解(Common Annotation)、字符串处理(Strings Processing)、数学计算(Math)、I/O、事件总线(EventBus)等等。

我截取了 Google Guava 的包结构图,贴到了这里,你看起来更加直观些。

在这里插入图片描述
我们知道,JDK 的全称是 Java Development Kit。它本身就是 Java 提供的工具类库。那现在请你思考一下,既然有了 JDK,为什么 Google 还要开发一套新的类库 Google Guava?是否是重复早轮子?两者的差异化在哪里?

带着这个问题,结合 Google Guava,我们来学习如何在业务开发中,发现通用的功能模块,以及如何将它开发成类库、框架或者功能组件。等到学习完之后,我希望你能自己回答这个问题。

如何发现通用的功能模块?

很多人觉得做业务开发没有挑战,实际上,做业务开发也会涉及很多非业务功能的开发,比如我们前面讲到的 ID 生成器、性能计数器、EventBus、DI 容器,以及后面会讲到的限流框架、幂等框架、灰度组件。关键在于,我们要有善于发现、善于抽象的能力,并且具有扎实的设计、开发能力,能够发现这些非业务的、可复用的功能点,并且从业务逻辑中将其解耦抽象出来,设计并开发成独立的功能模块。

在我看来,在业务开发中,跟业务无关的通用功能模块,常见的一般有三类:类库(library)、框架(framework)、功能组件(component)等。

其中,Google Guava 属于类库,提供一组 API 接口。EventBus、DI 容器属于框架,提供骨架代码,能让业务开发人员聚焦在业务开发部分,在预留的扩展点里填充业务代码。ID 生成器、性能计数器属于功能组件,提供一组具有某一特殊功能的 API 接口,有点类似类库,但更加聚焦和重量级,比如,ID 生成器有可能会依赖 Redis 等外部系统,不像类库那么简单。

前面提到的限流、幂等、灰度,到底是属于框架还是功能组件,我们要视具体情况而定。如果业务代码嵌套在它们里面开发,那就可以称它们为框架。如果它们只是开放 API 接口,供业务系统调用,那就可以称它们为组件。不过,叫什么没有太大关系,不必太深究概念。

那我们如何发现项目中的这些通用的功能模块呢?

实际上,不管是类库、框架还是功能组件,这些通用功能模块有两个最大的特点:复用和业务无关。Google Guava 就是一个典型的例子。

如果没有复用场景,那也就没有了抽离出来,设计成独立模块的必要了。如果与业务有关又可复用,大部分情况下会设计成独立的系统(比如微服务),而不是类库、框架或功能组件。所以,如果你负责开发的代码,与业务无关并且可能会被复用,那你就可以考虑将它独立出来,开发成类库、框架、功能组件等通用功能模块。

稍微补充一下,我们这里讲的是,在业务开发中,如何发现通用的功能模块。除了业务开发团队之外,很多公司还有一些基础架构团队、架构开发团队,他们除了开发类库、框架、功能组件之外,也会开发一些通用的系统、中间件,比如,Google MapReduce、Kafka 消息中间件、监控系统、分布式调用链追踪系统等。

如何开发通用的功能模块?

当我们发现了通用功能模块的开发需求之后,如何将它设计开发成一个优秀的类库、框架或功能组件呢?今天,我们不讲具体的开发技巧,具体的开发技巧在后面 Spring 开源实战那部分,我们会讲到一些,我今天打算先讲一些更普适的开发思想。我觉得先有了这些,你应该更容易理解后面的内容。

作为通用的类库、框架、功能组件,我们希望开发出来之后,不仅仅是自己项目使用,还能用在其他团队的项目中,甚至可以开源出来供更多人所用,这样才能发挥它更大的价值,构建自己的影响力。

所以,对于这些类库、框架、功能组件的开发,我们不能闭门造车,要把它们当作“产品”来开发。这个产品是一个“技术产品”,我们的目标用户是“程序员”,解决的是他们的“开发痛点”。我们要多换位思考,站在用户的角度上,来想他们到底想要什么样的功能。

对于一个技术产品来说,尽管 Bug 少、性能好等技术指标至关重要,但是否易用、易集成、易插拔、文档是否全面、是否容易上手等,这些产品素质也非常重要,甚至还能起到决定性作用。往往就是这些很容易忽视、不被重视的东西,会决定一个技术产品是否能在众多的同类中脱颖而出。

具体到 Google Guava,它是一个开发类库,目标用户是 Java 开发工程师,解决用户主要痛点是,相对于 JDK,提供更多的工具类,简化代码编写,比如,它提供了用来判断 null 值的 Preconditions 类;Splitter、Joiner、CharMatcher 字符串处理类;Multisets、Multimaps、Tables 等更丰富的 Collections 类等等。

它的优势有这样几点:第一,由 Google 管理、长期维护,经过充分的单元测试,代码质量有保证;第二,可靠、性能好、高度优化,比如 Google Guava 提供的 Immutable Collections 要比 JDK 的 unmodifiableCollection 性能好;第三,全面、完善的文档,容易上手,学习成本低,你可以去看下它的 Github Wiki。

刚刚讲的是“产品意识”,我们再来讲讲“服务意识”。我经常在团队中说,如果你开发的东西是提供给其他团队用的,你一定要有“服务意识”。对于程序员来说,这点可能比“产品意识”更加欠缺。

首先,从心态上,别的团队使用我们开发出来的技术产品,我们要学会感谢。这点很重要。心态不同了,做起事来就会有微妙的不同。其次,除了写代码,我们还要有抽出大量时间答疑、充当客服角色的心理准备。有了这个心理准备,别的团队的人在问你问题的时候,你也就不会很烦了。

相对于业务代码来说,开发这种被多处复用的通用代码,对代码质量的要求更高些,因为这些项目的影响面更大,一旦出现 bug,会牵连很多系统或其他项目。特别是如果你要把项目开源,影响就更大了。所以,这类项目的代码质量一般都很好,开发这类项目对代码能力的锻炼更有大。这也是我经常推荐别人通过阅读著名开源项目代码、参与开源项目来提高技术的原因。

具体到 Google Guava,它是 Google 员工开发的,单元测试很完善,注释写得很规范,代码写得也很好,可以说是学习 Google 开发经验的一手资料,建议你如果有时间的话,可以认真阅读一下它的代码。

尽管开发这些通用功能模块更加锻炼技术,但我们也不要重复造轮子,能复用的尽量复用。而且,在项目中,如果你想把所有的通用功能都开发为独立的类库、框架、功能组件,这就有点大动干戈了,有可能会得不到领导的支持。毕竟从项目中将这部分通用功能独立出来开发,比起作为项目的一部分来开发,会更加耗时。

所以,权衡一下的话,我建议初期先把这些通用的功能作为项目的一部分来开发。不过,在开发的时候,我们做好模块化工作,将它们尽量跟其他模块划清界限,通过接口、扩展点等松耦合的方式跟其他模式交互。等到时机成熟了,我们再将它从项目中剥离出来。因为之前模块化做的好,耦合程度低,剥离出来的成本也就不会很高。

重点回顾

好了,今天的内容到此就讲完了。我们一块来总结回顾一下,你需要重点掌握的内容。

做业务开发也会涉及很多非业务功能的开发。我们要有善于发现、善于抽象的能力,并且具有扎实的设计、开发能力,能够发现这些非业务的、可复用的功能点,并且从业务逻辑中将其解耦抽象出来,设计并开发成独立的功能模块,比如类库、框架、功能组件。

实际上,不管是类库、框架还是功能组件,这些通用功能模块最大的两个特点就是复用和业务无关。如果你开发的这块代码,业务无关并且可能会被复用,那就可以考虑将它独立出来,开发成类库、框架、功能组件等。

当我们发现了通用功能模块的开发需求之后,如何将它设计开发成一个优秀的类库、框架或功能组件呢?这里我们讲了一些更普适的开发思想,比如产品意识、服务意识、代码质量意识、不要重复造轮子等。

除此之外,我特别建议你去阅读一下 Google Guava 的开源代码。它的代码不复杂,很容易读懂,不会有太大阅读负担,但它是你获取 Google 公司开发经验的一手资料,特别是在单元测试、编码规范方面。

课堂讨论

针对你正在参与开发的项目,思考一下,有哪些通用的功能模块可以抽象出来,设计开发成独立的类库、框架、功能组件?它们都可能会包括哪些功能点呢?试着自己设计一下吧!

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

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

相关文章

智能指针类模板:auto_ptr、unique_ptr、shared_ptr的原理与使用

1. 什么是智能指针 智能指针是行为类似于指针的类对象,通常用于管理动态内存分配。C程序通常手动动态分配堆内存,但如果动态分配的内存没有释放,则会发生内存泄漏。 例如代码段1.1。 // 代码段1.1 void demo() {double *pd new double;*pd…

使用STM32F103的串口实现IAP程序升级功能

使用STM32F103的串口实现IAP程序升级功能 🎬IAP程序烧录全过程演示: ✨这几天折腾IAP升级功能,狂补了很多相关BootLoader相关的知识。本来最想实现IAP升级程序的方式是,基于SPI通讯的SD卡,借助挂载的FatFS文件系统&am…

C++中的内存分区

目录 操作系统的内存区域 C内存分区模型 1. 程序运行前 2. 程序运行后 3. new 操作符的使用 操作系统的内存区域 text段:存储程序的二进制指令,即程序源码编译后的二进制代码data段:存储已被初始化的全局变量、常量bss段:存储…

ES-工作原理

前言 ​ 搜索引擎是对数据的检索,而数据总体分为两种:结构化数据和非结构化数据。而对于结构化数据,因为他们具有特定的结构,所以一般都是可以通过关系型数据库MySQL/oracle的二维表的方式存储和搜索,也可以建立索引。…

Redis的简单使用 (实现Session持久化)

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、Redis数据类型的使用 1. 字符串&#xff…

Redis【入门篇】---- Redis的Java客户端-Jedis

Redis【入门篇】---- Redis的Java客户端-Jedis 1. Jedis快速入门2. Jedis连接池1. 创建Jedis连接池2. 改造原始代码 在Redis官网中提供了各种语言的客户端,地址:https://redis.io/docs/clients/ 其中Java客户端也包含很多: 标记为❤的就是推荐…

密码学证明方案寒武纪大爆发——扩容、透明性和隐私的变革潜力

1. 引言 前序博客有: ZKP大爆炸 本文主要参考: StarkWare 2023年6月博客 Cambrian Explosion of Cryptographic Proofs----The transformative potential for scalability, transparency, and privacy2023年3月Eli Ben-Sasson在The 13th BIU Winter …

JavaWeb之Cookie和Session

文章目录 CookieCookie基本介绍Cookie的基本使用Cookie的创建从服务器获取CookieCookie值的修改方案一方案二 浏览器查看CookieCookie声明控制Cookie有效路径Path的设置 SessionSession基本介绍Session的创建和获取(id号,是否为新)Session域数…

【SQL server关键字】

目录: 前言一、CREATE -- 创建二、INSERT INTO VALUES -- 插入数据三、SELECT FROM -- 查找数据1.SEKECT简单了解2.函数的使用3.选择列表与group by子句的对应4.exists子查询 四、UPDATE SET -- 更改数据五、ALTER -- 修改属性六、JOIN ON-- 链接多个表1. join初…

JDBC 望舒客栈项目 万字详解

目录 一、前言 二、项目结构 三、准备工作 1.建立子包 : 2.导入jar包 : 3.工具类 : 1 Utility工具类 2 JDBCUtilsDruid工具类 4.导入配置文件 : 5.引入BasicDAO : 四、项目主体 1.界面显示 : 1 代码演示 2 运行测试 2.用户登录 : 1 创建员工表employee 2 创建Ja…

JavaScript 事件加载有哪些应用场景?

💂 个人网站:【海拥】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 目录 前言什么是JavaScript事…

VUE L MVVM模型 ③

目录 文章有误请指正,如果觉得对你有用,请点三连一波,蟹蟹支持✨ V u e j s Vuejs Vuejs M V V M MVVM MVVM模型Data与El的2种写法总结 文章有误请指正,如果觉得对你有用,请点三连一波,蟹蟹支持✨ ⡖⠒⠒⠒…

多线程中的wait和notify

1、wait和notify 由于线程之间是抢占式执行的,所以线程之间的执行先后顺序难以预知。但实际上是希望合理的协调多个线程之间的执行先后顺序。 完成这个协调工作,主要涉及到三个方法 *wait()/wait(long timeout);让当前线程进入等待状态。 *notify()/n…

【每日算法 数据结构(C++)】—— 02 | 数组的并交集(解题思路、流程图、代码片段)

文章目录 01 | 👑 题目描述02 | 🔋 解题思路交集并集 03 | 🧢 代码片段交集并集 When you feel like giving up, remember why you started. 当你想放弃时,请记住为什么你开始 01 | 👑 题目描述 给你两个数组&#xff…

学习机组过程中的疑难问题与解决 -----(1)

本文章是在学习计算机组成原理过程中个人感觉需要理解与记忆的问题,还有一些在学习过程中自己产生的疑问以及解答,本文章可能排版不良,精力有限,还请见谅 第一章: (1)MAR的位数对应着存储单元的个数&#…

前端三剑客简介

文章目录 css的导入方式CSS选择器 JavascriptJavascript的引入方式输出语句变量数据类型javascript对象String对象 BOM对象DOM对象 W3C标准:网页主要由三部分组成 结构:html表现:css,层叠样式表行为:JavaScript css的…

VulnHub项目:Nagini

1、靶机地址: HarryPotter: Nagini ~ VulnHub 本篇为哈利波特死亡圣器系列的第二部,该靶机中存在3个魂器,依次找到它们,摧毁它们! 2、渗透过程 首先收集靶机ip和确定攻击机ip,同时探测靶机开放端口 存在…

一个简单案例理解为什么在多线程的应用中要使用互斥锁

需求:使用10个线程,同时对一个值count进行加一操作,每个线程对count加100000次,最终使得count1000000 第一版代码:不加锁 ​​​lock.c #include<stdio.h> #include<pthread.h>#define THREAD_COUNT 10void *thread_callback(void *arg){int *pcount(int*)arg;in…

Unity例子——第一人称视角的角色控制器

本文是为了前文Unity四元组的举例示范&#xff0c;为了让读者更好地理解。 效果是实现一个可以由鼠标进行方向操作&#xff0c;键盘进行移动操作的任务。 此为效果视频&#xff1a; 1687597097844 下面进行教学&#xff1a; 一、搭建简单场景 新建一个场景&#xff0c;放置一…