设计模式之美
王争
前 Google 工程师,《数据结构与算法之美》专栏作者
123426 人已学习
新⼈⾸单¥98
登录后,你可以任选6讲全文学习
课程目录
已完结/共 113 讲
设计模式与范式:行为型 (18讲)
设计模式之美
15
15
1.0x
00:00/00:00
登录|注册

77 | 开源实战一(下):通过剖析Java JDK源码学习灵活应用设计模式

创建快照的方式避免加锁导致性能问题
为了保证并发性能,采用了一种折中的方案
用于表明被观察者是否有状态更新
changed成员变量的必要性
synchronized大锁对并发性能的影响
迭代器模式
职责链模式
享元模式
单例模式
观察者模式
模板模式
适配器模式
装饰器模式
建造者模式
工厂模式
Java中Iterator迭代器的实现
Spring中的interceptor
Java Servlet中的Filter
String类型中的常量字符串
Integer类中的整型对象
Java AbstractList
Java InputStream
JUnit TestCase
Java Servlet
通过getRuntime()静态方法获取实例
饿汉式的单例实现方式
notifyObservers()函数
changed成员变量
java.util.Observer
java.util.Observable
与JdbcTemplate类似,基于Callback回调机制实现
委派比较大小逻辑给用户实现
使用模板模式的扩展特性
观察者模式的代码实现
真实项目开发中的灵活应用设计模式
其他模式
已剖析的设计模式
迭代器模式
职责链模式
享元模式
模板模式
Runtime类
Observable
Java JDK提供的简单框架实现
Collections.sort()
课堂讨论
重点回顾
其他模式在JDK中的应用汇总
单例模式
观察者模式
模板模式
Java JDK中设计模式的应用

该思维导图由 AI 生成,仅供参考

上一节课,我们讲解了工厂模式、建造者模式、装饰器模式、适配器模式在 Java JDK 中的应用,其中,Calendar 类用到了工厂模式和建造者模式,Collections 类用到了装饰器模式、适配器模式。学习的重点是让你了解,在真实的项目中模式的实现和应用更加灵活、多变,会根据具体的场景做实现或者设计上的调整。
今天,我们继续延续这个话题,再重点讲一下模板模式、观察者模式这两个模式在 JDK 中的应用。除此之外,我还会对在理论部分已经讲过的一些模式在 JDK 中的应用做一个汇总,带你一块回忆复习一下。
话不多说,让我们正式开始今天的学习吧!

模板模式在 Collections 类中的应用

我们前面提到,策略、模板、职责链三个模式常用在框架的设计中,提供框架的扩展点,让框架使用者,在不修改框架源码的情况下,基于扩展点定制化框架的功能。Java 中的 Collections 类的 sort() 函数就是利用了模板模式的这个扩展特性。
首先,我们看下 Collections.sort() 函数是如何使用的。我写了一个示例代码,如下所示。这个代码实现了按照不同的排序方式(按照年龄从小到大、按照名字字母序从小到大、按照成绩从大到小)对 students 数组进行排序。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了Java JDK源码中模板模式和观察者模式的应用。在模板模式方面,通过Collections类的sort()函数展示了模板模式的扩展特性,允许用户在不修改框架源码的情况下定制化框架的功能。同时,对sort()函数的实现进行了深入讨论,展现了其与模板模式和策略模式的关系,以及灵活的设计。在观察者模式方面,介绍了Java JDK中的Observable和Observer类,探讨了其实现中的设计考虑和性能优化,特别是对notifyObservers()函数的深入分析。通过这些实际的应用案例,读者可以更好地理解设计模式在实际项目中的灵活应用和技术细节。此外,文章还总结了其他设计模式在JDK中的应用,如单例模式、享元模式、职责链模式、迭代器模式等。总体而言,本文内容深入浅出,适合读者快速了解Java JDK源码中设计模式的应用特点,以及在真实项目开发中如何灵活应用设计模式。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《设计模式之美》
新⼈⾸单¥98
立即购买
登录 后留言

全部留言(29)

  • 最新
  • 精选
  • jxs1211
    文章中说Vector不是线程安全的,但是addElement和removeElement都是加了synchronized的呀,为什么不是线程安全的呢

    作者回复: 这个问题你可以搜下,很多文章有讲解。我摘抄了一段: vector的使用主要有如下两种场景: (1)vector所谓的多线程安全,只是针对单纯地调用某个方法它是有同步机制的。如add,多个线程都在对同一个容器add元素,vector能够保证最后总数是正确的,而ArrayList没有同步机制,就无法保证。 (2)vector的多线程安全,在组合操作时不是线程安全的。比如一个线程先调用vector的size方法得到有10个元素,再调用get(9)方法获取最后一个元素,而另一个线程调用remove(9)方法正好删除了这个元素,那第一个线程就会抛越界异常。

    2020-07-01
    4
    4
  • 汝林外史
    为什么说Vector不是线程安全的类呢?? Vector的方法不都加了synchronize关键字实现串行化并发安全了吗,应该是线程安全的类啊。

    作者回复: 这个你上网搜搜吧,一堆讲这个问题的。

    2020-04-29
    8
    4
  • Darren
    1、肯定会影响性能,但是因为保存观察者对象的必须是线程安全的,所以是不可避免,根据实际业务场景,如果很少被修改,可以使用CopyOnWriteArrayList来实现,但是如果修改频繁,CopyOnWriteArrayList 本质是写时复制,所以比较消耗内存,不建议使用,可以使用别的,比如ConcurrentSkipListSet等; 2、change是必须的,有些场景下(比如报警),状态发生变化其实是不报警,持续一定的时间菜报警,所以,把被观察者的对象是否发生变化独立出来,是可以做很多自己业务的事情;可以接单的理解为对变化抽象,提高可扩展性。
    2020-04-29
    1
    68
  • 小晏子
    思考题: 1. 每个函数加一把Synchronized锁,在并发激烈的时候是会影响性能的,优化的方式的话确实是可以使用CopyOnWriteList,copyOnWriteList是个并发安全的List,并且它不是基于锁实现的,而且又因为Oberser 中的List很少被修改经常被遍历的特点,所以使用CopyOnWriteList性能会提升。 2. changed成员变量还是必须的,这么做的好处是可以将“跟踪变化”和“通知观察者”两步分开,处理一些复杂的逻辑,
    2020-04-29
    6
    19
  • djfhchdh
    1、方案一:使用性能更好的线程安全的容器,来替换vector;方案二:如果没有多线程添加、删除观察者的操作,而是在程序启动时就定义好了观察者,以后也不会变更的话,就不用给相关函数加锁了。 2、changed成员不是多此一举,如果没有这个成员,notifyObservers()函数在多线程场景下,会出现重复通知观察者的情况。
    2020-04-29
    4
    15
  • 3Spiders
    思考题 1,是否能用异步观察者模式,减少并发压力。 2,change必须,如果没有change,那在notifyObservers同步拷贝观察者对象进行通知时,如果这时候有新的变更,那被观察者又会被通知一次。
    2020-04-29
    1
    10
  • 辣么大
    notifyObservers()这个方法写的巧妙呀!在高并发环境提高性能可以选择“折中“方案,控制锁的粒度。不禁感慨,人生面临的各种选择也是这样,也是各种妥协和折中。 使用cow遍历性能高,是因为不需要“复制”,它把复制的空间和时间开销,挪到了add之类的操作上,这也是一种折中。
    2020-05-04
    1
    8
  • Jxin
    1.会,写多场景可以采用分治思想降低锁冲突,数据量不大且写少场景就采用cow拿空间换时间。 2.有这个change字段可能导致丢失通知的情况。并发多个线程发送通知,保障至少一个线程发送通知的场景可以用。
    2020-04-29
    1
    5
  • Edward Lee
    课后思考 1. 使用 CopyOnWriteArrayList snapshot 方式提高性能 2. changed 变量是多此一举,在共享同一个 Observable 对象时,并发情况下甚至会出现通知丢失,这是因为 setChanged() 和 notifyObservers(args) 并不具备原子性,所以多个线程在 setChanged() 后都会被阻塞在 notifyObservers() 方法内,最终所有阻塞的线程都会全部通知失效。很多时候,像注册后通知就必须要能够通知到注册者,因此也不能容忍通知丢失的情况。
    2020-05-28
    1
    4
  • Heaven
    1.肯定降低了性能,而通常优化的手段,是更小粒度的锁或者使用乐观锁,在这个方法中已经将notifyObservers方法原本的大锁,利用一个复制技术缩小到一小点了,也是一种版本控制的方式,这里先给出一个尝试优化,使用原子类Boolean来替换setChanged这个大锁,并且使用copyonwriteArrayList来替换我们的数组 2.如果没有多并发的任何情况,changed的设计就是多此一举了,但是如果出现了高并发,那么直接去尝试直接执行更新操作可能会是一个非常漫长的等待,于是利用一个简单的标识位,并加上了锁来进行了修改,在高并发的情况下,无可厚非
    2020-04-29
    3
收起评论
显示
设置
留言
29
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部