当前位置: 首页 > news >正文

设计模式-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迭代器的实现。

http://www.lryc.cn/news/248848.html

相关文章:

  • Vue框架学习笔记——事件scroll和wheel的区别
  • 【LeetCode】每日一题 2023_11_29 无限集中的最小数字(哈希/堆)
  • C/C++ 常用的四种查找算法
  • Linux | Ubuntu设置 netstat(网络状态)
  • 成为AI产品经理——模型构建流程(下)
  • TCP Socket API 讲解,以及回显服务器客户端的实现
  • 2023年掌控安全学院CTF暖冬杯——数据流分析
  • UE4 基础篇十四:自定义插件
  • QT QGraphicsItem 图元覆盖导致鼠标点击事件不能传递到被覆盖图元
  • proto语法学习笔记
  • python-nmap库使用教程(Nmap网络扫描器的Python接口)(功能:主机发现、端口扫描、操作系统识别等)
  • 什么是智慧工地?
  • 【古月居《ros入门21讲》学习笔记】08_发布者Publisher的编程实现
  • 沿着马可·波罗的足迹,看数字云南
  • 记录问题-使用@Validated报错Validation failed for argument [0]
  • three.js--立方体
  • App的测试,和传统软件测试有哪些区别?应该增加哪些方面的测试用例?
  • 改进LiteOS中物理内存分配算法(详细实验步骤+相关源码解读)
  • 洛谷100题DAY8
  • 2. OpenHarmony源码下载
  • flask app.config 用法
  • 【Vue】【uni-app】实现工单列表项详情页面
  • 安装vmware_esxi 超详细
  • Spring-Mybatis源码解析--手写代码实现Spring整合Mybatis
  • 5.2 Windows驱动开发:内核取KERNEL模块基址
  • 聊聊Go语言的注释
  • 皮肤警告,羊大师讲解身体与环境的默契
  • 使用NVM管理多个Nodejs版同时支持vue2、vue3
  • Android帝国之进程杀手--lmkd
  • 堆栈_队列实现栈