设计模式
文章平均质量分 78
鸭梨山大哎
life hard take it easy
展开
-
编程语言的类型系统
另外,有些语言支持类型推断,例如Go语言和Scala语言,它们可以根据上下文自动推断变量类型,从而简化了类型注释的编写。类型系统可以使代码具有更好的文档和提示,从而帮助开发人员更快地理解和使用代码,减少代码的学习成本,提高代码的可读性和可维护性。例如,面向对象编程中的继承和多态性都需要类型系统的支持,而函数式编程中的强类型和静态类型语言更加注重类型的严格性和正确性。总之,类型系统可以通过类型检查、类型注释、清晰的代码组织、更好的文档和提示以及更好的工具和支持等方式提高代码的可读性和可维护性。原创 2023-05-07 10:25:00 · 566 阅读 · 0 评论 -
衡量失败检测算法的指标
失败发生的地方失败可能发生在节点之间的连接,比如丢包或者延迟增大;也可能发生在节点进程本身,比如节点崩溃或者处理缓慢。我们其实很难区分节点到底是处理慢,还是完全无法处理请求。所以所有的侦测算法需要在这两个状态中平衡,比如发现节点无法响应后,一般会在特定的延迟时间后再去侦测,从而更准确地判断节点到底处于哪种状态。衡量失败算法的指标活跃性活跃性指的是任何失败的消息都能被安全地处理,也就是如果一个节点失败了而无法响应正常的请求,它一定会被算法检测出来,而不会产生遗漏。安全性安全性则相反,算法不产生任何原创 2021-08-06 17:40:02 · 210 阅读 · 0 评论 -
针对非业务的通用框架开发,如何做需求分析和设计?
项目背景我们希望设计开发一个小的框架,能够获取接口调用的各种统计信息,比如,响应时间的最大值(max)、最小值(min)、平均值(avg)、百分位值(percentile)、接口调用次数(count)、频率(tps) 等,并且支持将统计结果以各种显示格式(比如:JSON 格式、网页格式、自定义显示格式等)输出到各种终端(Console 命令行、HTTP 网页、Email、日志文件、自定义输出终端等),以方便查看。我们假设这是真实项目中的一个开发需求,如果让你来负责开发这样一个通用的框架,应用到各种业务系转载 2021-07-03 10:12:55 · 338 阅读 · 0 评论 -
如何实现一个遵从设计原则的积分兑换系统2
业务开发包括哪些工作?实际上,我们平时做业务系统的设计与开发,无外乎有这样三方面的工作要做:接口设计、数据库设计和业务模型设计(也就是业务逻辑)。数据库和接口的设计非常重要,一旦设计好并投入使用之后,这两部分都不能轻易改动。改动数据库表结构,需要涉及数据的迁移和适配;改动接口,需要推动接口的使用者作相应的代码修改。这两种情况,即便是微小的改动,执行起来都会非常麻烦。因此,我们在设计接口和数据库的时候,一定要多花点心思和时间,切不可过于随意。相反,业务逻辑代码侧重内部实现,不涉及被外部依赖的接口,也不包含原创 2021-07-03 09:42:53 · 313 阅读 · 0 评论 -
针对业务系统的开发,如何做需求分析和设计1
今天,我通过一个积分兑换系统的开发实战,一方面给你展示一个业务系统从需求分析到上线维护的整个开发套路,让你能举一反三地应用到所有其他系统的开发中,另一方面也给你展示在看似没有技术含量的业务开发中,实际上都蕴含了哪些设计原则、思想、模式。需求分析积分是一种常见的营销手段,很多产品都会通过它来促进消费、增加用户粘性,比如淘宝积分、信用卡积分、商场消费积分等等。假设你是一家类似淘宝这样的电商平台的工程师,平台暂时还没有积分系统。Leader 希望由你来负责开发这样一个系统,你会如何来做呢?你可能会说,只要产原创 2021-07-03 09:25:35 · 1265 阅读 · 0 评论 -
依赖反转原则(DIP)
依赖反转原则。依赖反转原则的英文翻译是 Dependency Inversion Principle,缩写为 DIP。中文翻译有时候也叫依赖倒置原则。为了追本溯源,我先给出这条原则最原汁原味的英文描述:High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on detail原创 2021-07-01 21:51:26 · 606 阅读 · 1 评论 -
依赖注入框架(DI Framework)
在采用依赖注入实现的 Notification 类中,虽然我们不需要用类似 hard code 的方式,在类内部通过 new 来创建 MessageSender 对象,但是,这个创建对象、组装(或注入)对象的工作仅仅是被移动到了更上层代码而已,还是需要我们程序员自己来实现。具体代码如下所示:public class Demo { public static final void main(String args[]) { MessageSender sender = new SmsSende原创 2021-07-01 21:46:11 · 540 阅读 · 0 评论 -
依赖注入(DI)入门
依赖注入的英文翻译是 Dependency Injection,缩写为 DI。对于这个概念,有一个非常形象的说法,那就是:依赖注入是一个标价 25 美元,实际上只值 5 美分的概念。也就是说,这个概念听起来很“高大上”,实际上,理解、应用起来非常简单。那到底什么是依赖注入呢?我们用一句话来概括就是:不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用。我们还是通过一个例子来解释一下。在这个例子中,Notification原创 2021-07-01 21:42:06 · 437 阅读 · 0 评论 -
控制反转(IOC)入门
控制反转的英文翻译是 Inversion Of Control,缩写为 IOC。此处我要强调一下,如果你是 Java 工程师的话,暂时别把这个“IOC”跟 Spring 框架的 IOC 联系在一起。关于 Spring 的 IOC,我们待会儿还会讲到。我们先通过一个例子来看一下,什么是控制反转。public class UserServiceTest { public static boolean doTest() { // ... } public static void原创 2021-07-01 21:34:45 · 166 阅读 · 0 评论 -
Mybatis 和 ORM 框架介绍
熟悉 Java 的同学应该知道,MyBatis 是一个 ORM(Object Relational Mapping,对象 - 关系映射)框架。ORM 框架主要是根据类和数据库表之间的映射关系,帮助程序员自动实现对象与数据库中数据之间的互相转化。说得更具体点就是,ORM 负责将程序中的对象存储到数据库中、将数据库中的数据转化为程序中的对象。实际上,Java 中的 ORM 框架有很多,除了刚刚提到的 MyBatis 之外,还有 Hibernate、TopLink 等在剖析 Spring 框架的时候,我们讲到,原创 2021-06-20 09:23:22 · 6244 阅读 · 1 评论 -
Spring 框架蕴含的设计思想
在 Google Guava 源码讲解中,我们讲到开发通用功能模块的一些比较普适的开发思想,比如产品意识、服务意识、代码质量意识、不要重复早轮子等。今天,我们剖析一下 Spring 框架背后的一些经典设计思想(或开发技巧)。这些设计思想并非 Spring 独有,都比较通用,能借鉴应用在很多通用功能模块的设计开发中。这也是我们学习 Spring 源码的价值所在。1. 约定优于配置在使用 Spring 开发的项目中,配置往往会比较复杂、繁琐。比如,我们利用 Spring MVC 来开发 Web 应用,需要原创 2021-06-19 18:13:21 · 764 阅读 · 0 评论 -
Spring 框架简单介绍
考虑到你可能不熟悉 Spring,我这里对它做下简单介绍。我们常说的 Spring 框架,是指 Spring Framework 基础框架。Spring Framework 是整个 Spring 生态(也被称作 Spring 全家桶)的基石。除了 Spring Framework,Spring 全家桶中还有更多基于 Spring Framework 开发出来的、整合更多功能的框架,比如 Spring Boot、Spring Cloud。在 Spring 全家桶中,Spring Framework 是最基础原创 2021-06-19 17:59:24 · 539 阅读 · 0 评论 -
Java 对函数式编程的支持
我们前面讲到,实现面向对象编程不一定非得使用面向对象编程语言,同理,实现函数式编程也不一定非得使用函数式编程语言。现在,很多面向对象编程语言,也提供了相应的语法、类库来支持函数式编程。接下来,我们就看下 Java 这种面向对象编程语言,对函数式编程的支持,借机加深一下你对函数式编程的理解。我们先来看下面这样一段非常典型的 Java 函数式编程的代码。public class FPDemo { public static void main(String[] args) { Optional&原创 2021-06-19 17:51:28 · 406 阅读 · 0 评论 -
什么是函数式编程?
函数式编程的英文翻译是 Functional Programming。 那到底什么是函数式编程呢?在前面的章节中,我们讲到,面向过程、面向对象编程并没有严格的官方定义。在当时的讲解中,我也只是给出了我自己总结的定义。而且,当时给出的定义也只是对两个范式主要特性的总结,并不是很严格。实际上,函数式编程也是如此,也没有一个严格的官方定义。所以,接下来,我就从特性上来告诉你,什么是函数式编程。严格上来讲,函数式编程中的“函数”,并不是指我们编程语言中的“函数”概念,而是指数学“函数”或者“表达式”(比如,y=原创 2021-06-19 17:41:59 · 3586 阅读 · 0 评论 -
Builder 模式在 Guava 中的应用
在项目开发中,我们经常用到缓存。它可以非常有效地提高访问速度。常用的缓存系统有 Redis、Memcache 等。但是,如果要缓存的数据比较少,我们完全没必要在项目中独立部署一套缓存系统。毕竟系统都有一定出错的概率,项目中包含的系统越多,那组合起来,项目整体出错的概率就会升高,可用性就会降低。同时,多引入一个系统就要多维护一个系统,项目维护的成本就会变高。取而代之,我们可以在系统内部构建一个内存缓存,跟系统集成在一起开发、部署。那如何构建内存缓存呢?我们可以基于 JDK 提供的类,比如 HashMap,原创 2021-06-19 17:31:17 · 313 阅读 · 0 评论 -
借Google Guava学习发现和开发通用功能模块
如何发现通用的功能模块?很多人觉得做业务开发没有挑战,实际上,做业务开发也会涉及很多非业务功能的开发,比如我们前面讲到的 ID 生成器、性能计数器、EventBus、DI 容器,以及后面会讲到的限流框架、幂等框架、灰度组件。关键在于,我们要有善于发现、善于抽象的能力,并且具有扎实的设计、开发能力,能够发现这些非业务的、可复用的功能点,并且从业务逻辑中将其解耦抽象出来,设计并开发成独立的功能模块。在我看来,在业务开发中,跟业务无关的通用功能模块,常见的一般有三类:类库(library)、框架(framew原创 2021-06-19 15:16:17 · 147 阅读 · 0 评论 -
从Unix开源开发学习应对大型复杂项目开发
封装与抽象在 Unix、Linux 系统中,有一句经典的话,“Everything is a file”,翻译成中文就是“一切皆文件”。这句话的意思就是,在 Unix、Linux 系统中,很多东西都被抽象成“文件”这样一个概念,比如 Socket、驱动、硬盘、系统信息等。它们使用文件系统的路径作为统一的命名空间(namespace),使用统一的 read、write 标准函数来访问。比如,我们要查看 CPU 的信息,在 Linux 系统中,我们只需要使用 Vim、Gedit 等编辑器或者 cat 命令原创 2021-06-10 23:22:50 · 173 阅读 · 0 评论 -
装饰器模式在 Collections 类中的应用
我们前面讲到,Java IO 类库是装饰器模式的非常经典的应用。实际上,Java 的 Collections 类也用到了装饰器模式。Collections 类是一个集合容器的工具类,提供了很多静态方法,用来创建各种集合容器,比如通过 unmodifiableColletion() 静态方法,来创建 UnmodifiableCollection 类对象。而这些容器类中的 UnmodifiableCollection 类、CheckedCollection 和 SynchronizedCollection 类原创 2021-06-07 22:45:54 · 148 阅读 · 0 评论 -
工厂模式在 Calendar 类中的应用
在前面讲到工厂模式的时候,大部分工厂类都是以 Factory 作为后缀来命名,并且工厂类主要负责创建对象这样一件事情。但在实际的项目开发中,工厂类的设计更加灵活。那我们就来看下,工厂模式在 Java JDK 中的一个应用:java.util.Calendar。从命名上,我们无法看出它是一个工厂类。Calendar 类提供了大量跟日期相关的功能代码,同时,又提供了一个 getInstance() 工厂方法,用来根据不同的 TimeZone 和 Locale 创建不同的 Calendar 子类对象。也就是说,原创 2021-06-07 22:39:01 · 413 阅读 · 0 评论 -
策略模式入门
策略模式,英文全称是 Strategy Design Pattern。在 GoF 的《设计模式》一书中,它是这样定义的:Define a family of algorithms, encapsulate each one, and make theminterchangeable. Strategy lets the algorithm vary independently fromclients that use it.翻译成中文就是:定义一族算法类,将每个算法分别封装起来,让它们可以互相替原创 2021-06-07 22:30:51 · 156 阅读 · 0 评论 -
模板方法模式入门
模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。这里的“算法”,我们可以理解为广义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“.原创 2021-06-07 22:20:18 · 97 阅读 · 0 评论 -
备忘录模式入门
备忘录模式,也叫快照(Snapshot)模式,英文翻译是 Memento Design Pattern。在 GoF 的《设计模式》一书中,备忘录模式是这么定义的:Captures and externalizes an object’s internal state so that it can berestored later, all without violating encapsulation.翻译成中文就是:在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以原创 2021-06-07 22:05:44 · 199 阅读 · 0 评论 -
观察者模式入门
观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。在 GoF 的《设计模式》一书中,它的定义是这样的:Define a one-to-many dependency between objects so that when oneobject changes state, all its dependents are notified and updatedautomatically.翻译成中文就原创 2021-06-06 17:52:28 · 91 阅读 · 0 评论 -
享元模式在 Java Integer 中的应用
我们先来看下面这样一段代码。你可以先思考下,这段代码会输出什么样的结果。Integer i1 = 56;Integer i2 = 56;Integer i3 = 129;Integer i4 = 129;System.out.println(i1 == i2);System.out.println(i3 == i4);如果不熟悉 Java 语言,你可能会觉得,i1 和 i2 值都是 56,i3 和 i4 值都是 129,i1 跟 i2 值相等,i3 跟 i4 值相等,所以输出结果应该是两个原创 2021-06-06 16:17:40 · 201 阅读 · 0 评论 -
享元模式在文本编辑器中的应用
如何利用享元模式来优化文本编辑器的内存占用?你可以把这里提到的文本编辑器想象成 Office 的 Word。不过,为了简化需求背景,我们假设这个文本编辑器只实现了文字编辑功能,不包含图片、表格等复杂的编辑功能。对于简化之后的文本编辑器,我们要在内存中表示一个文本文件,只需要记录文字和格式两部分信息就可以了,其中,格式又包括文字的字体、大小、颜色等信息。尽管在实际的文档编写中,我们一般都是按照文本类型(标题、正文……)来设置文字的格式,标题是一种格式,正文是另一种格式等等。但是,从理论上讲,我们可以给文本原创 2021-06-06 16:01:33 · 177 阅读 · 0 评论 -
享元模式入门
所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。具体来讲,当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,我们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。这样可以减少内存中对象的数量,起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段)提取出来,设计成享元,让这些大量相似对象引用这些享元。这里我稍微解释一下,定义中的“不可变对象”指的是,原创 2021-06-06 15:53:04 · 104 阅读 · 0 评论 -
代理模式的原理解析入门
什么是代理模式?它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。我们通过一个简单的例子来解释一下这段话。这个例子来自我们在第 25、26、39、40 节中讲的性能计数器。当时我们开发了一个 MetricsCollector 类,用来收集接口请求的原始数据,比如访问时间、处理时长等。在业务系统中,我们采用如下方式来使用这个 MetricsCollector 类:public class UserController { //...省略其他属性和方法... pr原创 2021-06-06 15:46:12 · 226 阅读 · 0 评论 -
适配器模式在 Java 日志中的应用
Java 中有很多日志框架,在项目开发中,我们常常用它们来打印日志信息。其中,比较常用的有 log4j、logback,以及 JDK 提供的 JUL(java.util.logging) 和 Apache 的 JCL(Jakarta Commons Logging) 等。大部分日志框架都提供了相似的功能,比如按照不同级别(debug、info、warn、erro……)打印日志等,但它们却并没有实现统一的接口。这主要可能是历史的原因,它不像 JDBC 那样,一开始就制定了数据库操作的接口规范。如果我们只是原创 2021-06-06 09:11:14 · 156 阅读 · 0 评论 -
适配器模式的原理与实现
适配器模式的英文翻译是 Adapter Design Pattern。顾名思义,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,有一个经常被拿来解释它的例子,就是 USB 转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。原理很简单,我们再来看下它的代码实现。适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。具体的代码实现如下所示。其中,ITar原创 2021-06-06 09:03:41 · 610 阅读 · 0 评论 -
门面模式入门
如果你平时的工作涉及接口开发,不知道你有没有遇到关于接口粒度的问题呢?为了保证接口的可复用性(或者叫通用性),我们需要将接口尽量设计得细粒度一点,职责单一一点。但是,如果接口的粒度过小,在接口的使用者开发一个业务功能时,就会导致需要调用 n 多细粒度的接口才能完成。调用者肯定会抱怨接口不好用。相反,如果接口粒度设计得太大,一个接口返回 n 多数据,要做 n 多事情,就会导致接口不够通用、可复用性不好。接口不可复用,那针对不同的调用者的业务需求,我们就需要开发不同的接口来满足,这就会导致系统的接口无限膨胀。原创 2021-06-06 08:48:53 · 368 阅读 · 0 评论 -
为什么java IO类不用基于继承的设计方案?
在我初学 Java 的时候,曾经对 Java IO 的一些用法产生过很大疑惑,比如下面这样一段代码。我们打开文件 test.txt,从中读取数据。其中,InputStream 是一个抽象类,FileInputStream 是专门用来读取文件流的子类。BufferedInputStream 是一个支持带缓存功能的数据读取类,可以提高数据读取的效率。InputStream in = new FileInputStream("/user/wangzheng/test.txt");InputStream bi原创 2021-06-05 10:36:15 · 113 阅读 · 0 评论 -
原型模式的原理与应用
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。那何为“对象的创建成本比较大”?实际上,创建对象包含的申请内存、给成员变量赋值这一过程,本身并不会花费太多时间,或者说对于大部分业务系统来说,这点时间完全是可以忽略的。应用一个复杂的模式,只得到一点点的原创 2021-06-05 10:20:09 · 484 阅读 · 0 评论 -
为什么需要建设者模式
在平时的开发中,创建一个对象最常用的方式是,使用 new 关键字调用类的构造函数来完成。我的问题是,什么情况下这种方式就不适用了,就需要采用建造者模式来创建对象呢?你可以先思考一下,下面我通过一个例子来带你看一下。假设有这样一道设计面试题:我们需要定义一个资源池配置类 ResourcePoolConfig。这里的资源池,你可以简单理解为线程池、连接池、对象池等。在这个资源池配置类中,有以下几个成员变量,也就是可配置项。现在,请你编写代码实现这个 ResourcePoolConfig 类。只要你稍微有点原创 2021-06-05 10:10:55 · 268 阅读 · 0 评论 -
简单工厂模式入门
首先,我们来看,什么是简单工厂模式。我们通过一个例子来解释一下。在下面这段代码中,我们根据配置文件的后缀(json、xml、yaml、properties),选择不同的解析器(JsonRuleConfigParser、XmlRuleConfigParser……),将存储在文件中的配置解析成内存对象 RuleConfig。public class RuleConfigSource { public RuleConfig load(String ruleConfigFilePath) { St原创 2021-06-05 09:40:45 · 117 阅读 · 0 评论 -
迭代器模式的原理和实现
迭代器模式(Iterator Design Pattern),也叫作游标模式(Cursor Design Pattern)。在开篇中我们讲到,它用来遍历集合对象。这里说的“集合对象”也可以叫“容器”“聚合对象”,实际上就是包含一组对象的对象,比如数组、链表、树、图、跳表。迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一。迭代器是用来遍历容器的,所以,一个完整的迭代器模式一般会涉及容器和容器迭代器两部分内容。为了达到基于接口而非实现编程的目的,容器又包含容器接口、容器原创 2021-06-01 23:09:13 · 769 阅读 · 1 评论 -
为什么要重构(why)?
虽然对于你来说,重构这个词可能不需要过多解释,但我们还是简单来看一下,大师是怎么描述它的。软件设计大师 Martin Fowler 是这样定义重构的:“重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。”实际上,当讲到重构的时候,很多书籍都会引用这个定义。这个定义中有一个值得强调的点:“重构不改变外部的可见行为”。我们可以把重构理解为,在保持功能不变的前提下,利用设计思想、原则、模式、编程规范等理论来优化代码,修改设计上的不足,提高代码质量。简单了解重构的原创 2021-06-01 22:58:42 · 1663 阅读 · 0 评论 -
dry原则入门
DRY 原则。它的英文描述为:Don’t Repeat Yourself。中文直译为:不要重复自己。将它应用在编程中,可以理解为:不要写重复的代码。DRY 原则的定义非常简单,我就不再过度解读。今天,我们主要讲三种典型的代码重复情况,它们分别是:实现逻辑重复、功能语义重复和代码执行重复。这三种代码重复,有的看似违反 DRY,实际上并不违反;有的看似不违反,实际上却违反了。实现逻辑重复我们先来看下面这样一段代码是否违反了 DRY 原则。如果违反了,你觉得应该如何重构,才能让它满足 DRY 原则?如果没有原创 2021-06-01 22:47:22 · 325 阅读 · 0 评论 -
代码行数越少就越“简单”吗?
我们先一起看一个例子。下面这三段代码可以实现同样一个功能:检查输入的字符串 ipAddress 是否是合法的 IP 地址。一个合法的 IP 地址由四个数字组成,并且通过“.”来进行分割。每组数字的取值范围是 0~255。第一组数字比较特殊,不允许为 0。对比这三段代码,你觉得哪一段代码最符合 KISS 原则呢?如果让你来实现这个功能,你会选择用哪种实现方法呢?你可以先自己思考一下,然后再看我下面的讲解。// 第一种实现方式: 使用正则表达式public boolean isValidIpAddres原创 2021-06-01 22:35:01 · 291 阅读 · 0 评论 -
如何理解“KISS 原则”?
KISS 原则的英文描述有好几个版本,比如下面这几个。Keep It Simple and Stupid.Keep It Short and Simple.Keep It Simple and Straightforward.不过,仔细看你就会发现,它们要表达的意思其实差不多,翻译成中文就是:尽量保持简单。KISS 原则算是一个万金油类型的设计原则,可以应用在很多场景中。我们知道,代码的可读性和可维护性是衡量代码质量非常重要的两个标准。而 KISS 原则就是保持代码可读和可维护的重要手段。代码足原创 2021-06-01 22:31:05 · 579 阅读 · 0 评论 -
饿汉式单例入门
饿汉式的实现方式比较简单。在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载(在真正用到 IdGenerator 的时候,再创建实例),从名字中我们也可以看出这一点。具体的代码实现如下所示:public class IdGenerator { private AtomicLong id = new AtomicLong(0); private static final IdGenerator原创 2021-05-30 18:24:07 · 212 阅读 · 0 评论