⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 slideshare.net/miragemiko/new-java-features-simplified-design-patternslit3826 「Miroslav Wengner 与 Benedikt Neumayr」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

Java 平台与 OpenJDK

让我们从 Java 虚拟机开始。

  • 编译器负责生成字节码;
  • JIT 编译器负责优化成本地代码;
  • JVM 解释器负责输出期望结果。
  • 字节码优化技术:内联 inlining、消除 elimination、标量化 scalarization。

下面是一个优化后的结果示例:

static factory_method.Car produce(java.lang.String); 
descriptor: (Ljava/lang/String;)Lfactory_method/Car;
flags: (0x0008) ACC_STATIC
Code:
stack=7, locals=5, args_size=1
0: new #7 // class factory_method/FactoryMethodEvent
3: dup
...
19: aload_3
20: invokevirtual #17 // Method java/lang/String.hashCode:()I
23: lookupswitch { // 2
3135580: 48
3556498: 63
default: 75
}
48: aload_3
49: ldc #23 // String fast
51: invokevirtual #25 // Method java/lang/String.equals:(Ljava/lang/Object;)Z

用 SOLID 思想看设计模式

概述 SOLID 原则以及与现在开发需要考虑的一些设计原则:

  • SOLID 原则:单一功能、开闭原则、里氏替换、接口隔离以及依赖反转;
  • 不要重复自己,关注点分离,CAP 原则;
  • 编程语言和技术不可知;
  • 微服务架构、分布式系统领域驱动设计、数据流;
  • 可扩展性、可维护性与安全性。

设计模式分创建型、结构型、行为型,其中行为型设计模式需要考虑服务、运行时的并发。

一些重要项目

  • Valhalla 项目:利用通用 API、基础类型和值类型,提升机器学习和大数据应用程序性能

    • 隐藏类(JEP-371)、对值类型 class 进行警告 (JEP-390) 等
  • Panama 项目:为 JVM 和非 Java API 提供桥梁,可以更容易地实现 App 之间的 I/O

    • 外部函数和内存 API (JEP-424)、Vector API (JEP-426)等
  • Amber 项目:通过 Java 语言自身演进提升生产率

    • 局部变量类型推断 (JEP-286)、switch 表达式改进 (JEP-361)
    • TextBlocks (JEP-378)、Records (JEP-395), instanceof 的模式匹配 (JEP-394)
    • 密封类 (JEP-409)、默认支持 UTF-8 (JEP-400)、Record 模式 (JEP-405)等
  • Loom 项目: 易于使用,高吞吐量、轻量级并发和编程方法

    • 虚拟线程 (JEP-425)、结构化并发 (JEP-428)等

简化创建对象

  • 备选方案:Factory 或 Builder。二者有何区别?

    • 前者是封装,后者是逐步构建直到最后生产
    • 其它区别包括,如何补充信息、实现可测试性等
  • 其它选择:

    • 抽象工厂、原型模式、单例模式、 对象池延迟初始化、依赖注入

JDK 中使用 Builder:使用 StringBuilder 或者像下面这样:

public class Thread implements Runnable { //JDK19(Preview)
public sealed interface Builder permits Builder.OfPlatform,
Builder.OfVirtual, ThreadBuilders.BaseThreadBuilder {
..
}
}

JDK 中的工厂:使用 Java Collection framework,例如 List、Set 或者 Map。

static <E> List <E> of (E e1, E e2, E e3) {
return ImmutableCollections.listFromTrustedArray(e1, e2, e3);
}
static <K, V> Map <K, V> of (K k1, V v) {
return new ImmutableCollections.Map1 < > (k1, v1);
}

下面是 CarFactory 示例及运行效果:

record FastCar(String type) implements Car { ...
sealed interface Factory permits CarFactory { ...
final class CarFactory {
static Vehicle produce(String type) {
var result =
switch (type) {
case "fast" - > {
...
yield new FastCar(“super”);
}
case String s
when s.length() > 10 - > new SlowCar()
...

如何结构化思考

如何围绕实例化对象组织代码(指令)

  • 备选方案:适配器或享元模式;
  • 其它方案:组合模式、装饰器模式、外观模式(也称门面模式)、过滤器模式、模块模式、控制器模式、标记型接口、代理模式、双胞胎模式。

JDK 中的适配器:

public final class Spliterators { ...
public static <T> Iterator <T> iterator(Spliterator <<?extends T> spliterator) {
Objects.requireNonNull(spliterator);
class Adapter implements Iterator <T> , Consumer <T> {
...
}
}
}

public Collections {
...
public static <T> ArrayList <T> list(Enumeration <T> e) { ... }

JDK 中的友元:

Integer、Byte、Character 等包装类,以及 valueOf(...) 方法使用到的缓存:

return IntegerCache.cache[i + (-IntegerCache.low)];

下面是 Engine 密封接口示例及运行效果:

var engine = counter++ % 2 == 0 ? new DieselEngine() : new ElectricEngine();
var fastCar = new FastCar(engine);

class FastCar {
...
FastCar(Engine engine) {
...
}
public void drive() {
...
if (engine instanceof ElectricEngine ee) {
ee.checkBatteries();
}
engine.run();
...
sealed interface Engine {
void run();
}

运行时设置行为

运行时如何维护对象之间的信息传递?

由 JVM 和代码库提供灵活性和可维护性。

  • 备选方案:责任链模式、命令模式、缓存;
  • 其它方案:状态模式、策略模式、解释器模式、迭代器模式、中介者模式、 备忘录模式、Null 对象、观察者模式、管道、模板方法、访问者模式等。

JDK 中的责任链:

public class Logger {
public void log(Level level, Supplier < String > msgSupplier)
//overloaded method, Levels: OFF, SEVERE, WARNING ...

JDK 中的命令:

java.lang.Runnable, java.lang.Callable

JDK 中的缓存:

java.util.Locale
private static class Cache extends LocaleObjectCache < Object, Locale > {
private static final Cache LOCALECACHE = new Cache();

并发相关

那么并行执行的代码该如何考虑呢?

根据问题的多线程性质选择适合的设计模式组合。

  • 备选方案:线程池模式;
  • 其它方案:主动对象模式、异步方法调用、Balking 模式、双重检查锁定、读写锁、调度器等。

下图中可以看到并发相关 package 在 JDK 中的依赖关系(由 Java Mission Control 8.3 生成)

下面是一个使用虚拟线程的示例:

var threadPerTaskExecutor = Executors.newThreadPerTaskExecutor(threadFactory);
var executor = Executors.newVirtualThreadPerTaskExecutor();
threadPerTaskExecutor.execute(() - > {
while (active.get()) {
executor.submit(new ComputableTask(counter));
}
})

总结

设计模式和 JDK 新功能带来了以下好处:

  • 密封类、模式匹配让代码变得更清晰;
  • switch 语法改进、引入 Record 减少了冗余代码;
  • Amber 项目、Loom 项目增强了项目可维护性;
  • 虚拟线程、结构化并发、switch、局部变量类型推断让组合变得更简单;
  • 带来更好的可观测性、性能分析、调试功能。

参考资料

  • Amber项目: https://openjdk.org/projects/amber/
  • Valhalla项目: https://openjdk.org/projects/valhalla/
  • Panama项目: https://openjdk.org/projects/panama/
  • JFR项目: https://github.com/openjdk/jmc
  • OpenJDK: https://openjdk.org/
  • foojay.io: https://foojay.io/today/author/miro-wengner/
  • OpenValue博客: https://openvalue.blog/
  • Practical Design Patterns for Java Developers [PACKT]
文章目录
  1. 1. Java 平台与 OpenJDK
  2. 2. 用 SOLID 思想看设计模式
  3. 3. 简化创建对象
  4. 4. 如何结构化思考
  5. 5. 运行时设置行为
  6. 6. 并发相关
  7. 7. 总结
  8. 8. 参考资料