81 - 剖析Google Guava中用的设计模式(一)

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

  1. 对 Google Guava 做一个简单介绍,并借此讲一下如何开发一个通用的功能模块。
  2. 讲 Google Guava 中用到的几种设计模式,会补充讲解之前没有讲到的 Immutable 模式。
  3. 借 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 消息中间件、监控系统、分布式调用链追踪系统等。

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

  • 当我们发现了通用功能模块的开发需求之后,如何将它设计开发成一个优秀的类库、框架或功能组件呢?基于此,本文先讲一些更普适的开发思想。
  • 作为通用的类库、框架、功能组件,我们希望开发出来之后,不仅仅是自己项目使用,还能用在其他团队的项目中,甚至可以开源出来供更多人所用,这样才能发挥它更大的价值,构建自己的影响力。
  • 所以,对于这些类库、框架、功能组件的开发,我们不能闭门造车,要把它们当作“产品”来开发。这个产品是一个“技术产品”,我们的目标用户是“程序员”,解决的是他们的“开发痛点”。我们要多换位思考,站在用户的角度上,来想他们到底想要什么样的功能。
  • 对于一个技术产品来说,尽管 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 公司开发经验的一手资料,特别是在单元测试、编码规范方面。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容