NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

用现代 Java 调整经典设计模式

  • 2022-10-28
    北京
  • 本文字数:2955 字

    阅读完需:约 10 分钟

用现代Java调整经典设计模式

1998 年出版的《设计模式——可复用面向对象软件的基础》有资格成为计算机科学的经典著作,大学仍然将它作为教材,并被奉为业界的最佳实践。在 Devoxx 的一场深度讨论中,Venkat Subramaniam使用现代 Java 实现了迭代器策略装饰器工厂方法模式,对原有的设计模式进行了一番调整。


讨论的引言部分,Subramaniam 表示这本书的作者是软件开发的祖父,他们的设计模式是祖母的食谱——但即使你有了这些食谱,也不一定能做出这些菜。因此,他认为将设计模式作为一种沟通工具是有意义的,但将其作为一种软件设计工具却是一场灾难。


以下是我们在日常编程中可能遇到的常见模式,Subramaniam 通过充满活力和快乐的方式让这些模式变得更加流式。


由于 Java 加入了函数式编程,迭代器模式发生了很大的变化。最大的一个变化是从外部迭代器到内部迭代器的转变,这是 Java 函数式 API 带来的。这个变化可以让你从使用冗长的命令式迭代


int count = 0;for(var name: names) {   if(name.length() == 4) {     System.out.println(name.toUpperCase());   count++;
if(count == 2) { break; } } }}
复制代码


演变成使用流式的函数式迭代


names.stream()     .filter(name -> name.length() == 4)     .map(String::toUpperCase)     .limit(2)     .forEach(System.out::println);
复制代码


limit(long)takeWhile(Predicate<? super T>)(在 Java 9 中添加的)是continuebreak语句的等效函数,第一个只接受数值限制参数,而第二个可以接受表达式。


尽管 Java 的函数式 API 作为 JDK 的一部分已经有近十年的时间了,但在代码库中仍然存在一些常见的错误。当函数管道“不”纯粹(修改或依赖外部可见的状态)时,可能会导致迭代操作的结果不可预测(特别是在进行并行执行时)。


策略模式——我们希望改变算法的一小部分,同时保持算法的其余部分不变。从历史上看,这个模式是通过一个方法来实现的,这个方法采用一个方法接口作为参数,作为参数的方法接口可以有多个策略实现,一个策略通常就是一个方法或函数。因此,函数式接口和 lambda 表达式在这里很适用。


虽然匿名类可以作为一种实现机制,但函数接口(Predicate<? super T>是一个很好的选择)或 lambda 表达式让代码变得更加流式,更容易理解。在现代 Java 中,策略模式更多的是一种特性,而不是需要付出大量努力才能实现的模式。


public class Sample {  public static int totalValues(List<Integer> numbers) {    int total = 0;
for(var number: numbers) { total += number; }
return total; }
public static int totalEvenValues(List<Integer> numbers) { int total = 0;
for(var number: numbers) { if(number % 2 == 0) { total += number; } }
return total; }
public static int totalOddValues(List<Integer> numbers) { int total = 0;
for(var number: numbers) { if(number % 2 != 0) { total += number; } }
return total; }
public static void main(String[] args) { var numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(totalValues(numbers)); System.out.println(totalEvenValues(numbers)); System.out.println(totalOddValues(numbers)); }}
复制代码


现代的做法是使用 lambda 表达式来表示策略。


import java.util.function.Predicate;
public class Sample { public static int totalValues(List<Integer> numbers, Predicate<Integer> selector) { int total = 0;
for(var number: numbers) { if(selector.test(number)) { total += number; } }
return total; }
public static boolean isOdd(int number) { return number % 2 != 0; }
public static void main(String[] args) { var numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(totalValues(numbers, ignore -> true)); System.out.println(totalValues(numbers, number -> number % 2 == 0));
System.out.println(totalValues(numbers, Sample::isOdd)); }}
复制代码


在介绍工厂方法实现时,Venkat 陈述了以下内容。


从多态的角度来看,Java 中最糟糕的关键字是什么?尽管 final、instanceof 和 static 都可能算是最糟糕的关键字,但它们都只是小兵,new才是它们当中的黑手党。多模式(创建模式)、框架(SpringGuice)是为了解决 new 的“弊端”——缺乏多态性支持和紧密耦合。受Ruby基于上下文创建不同对象的多态能力的启发,Venkat 使用 Java 的default关键字实现工厂方法模式。这种方法使用了接口和非常小的实现类,让代码变得更容易理解。


import java.util.*;
interface Pet {}class Dog implements Pet {}class Cat implements Pet {}
interface Person { Pet getPet();
default void play() { System.out.println("playing with " + getPet()); }}
class DogPerson implements Person { private Dog dog = new Dog();
public Pet getPet() { return dog; }}
class CatLover implements Person { private Cat cat = new Cat(); public Pet getPet() { return cat; }}
public class Sample { public static void call(Person person) { person.play(); }
public static void main(String[] args) { call(new DogPerson()); call(new CatLover()); }}
复制代码


即使装饰器模式在理论上为许多程序员所熟知,但实际上很少有人使用它。它的实现最臭名昭著的例子可能是 io 包。Venkat 基于函数的可组合性提出了一种不同的方法——使用identity函数和andThen(Function<? super R,? extends V>)构建简单、流式的机制来增强对象的能力。


class Camera {  private Function<Color, Color> filter;
public Camera(Function<Color, Color>... filters) { filter = Stream.of(filters) .reduce(Function.identity(), Function::andThen); }
public Color snap(Color input) { return filter.apply(input); }}
public class Sample { public static void print(Camera camera) { System.out.println(camera.snap(new Color(125, 125, 125))); }
public static void main(String[] args) { print(new Camera());
print(new Camera(Color::brighter)); print(new Camera(Color::darker));
print(new Camera(Color::brighter, Color::darker)); }}
复制代码


即使模式看起来会一直存在,就像 Subramaniam在讨论中提到的:“设计模式经常被用来填补编程语言的空白。一门语言越强大,我们就越少谈论设计模式,因为设计模式自然会成为语言的特性。”


随着编程语言的演进和我们经验的积累,模式也会随着时间的推移而演变。其中一些模式被吸收为语言的特性,另一些则被认为已过时,而另一些变得更加容易实现。不管你最喜欢的是哪一类,Venkat 建议把它们作为交流的手段,并让代码朝着这些模式的方向演变。此外,他建议尝试使用多种编程语言,让代码变得更加流式。


原文链接

https://www.infoq.com/news/2022/10/modern-java-design-patterns/

2022-10-28 09:558804

评论

发布
暂无评论
发现更多内容

腾讯AI Lab姚建华博士当选 2022 美国医学与生物工程院会士

科技热闻

车载小程序快马加鞭突围车联网生态系统

FinClip

“远见者”特斯拉AI主管Karpathy|深度学习崛起十年

OneFlow

人工智能 深度学习 计算机视觉 特斯拉 openai

产品知识在线培训的解决方案

小炮

企业知识管理

突破数据分析瓶颈,寻因生物单细胞测序数据分析迈入云时代

阿里云弹性计算

虚拟化 持久内存 基因测序

高效使用Java构建工具,Maven篇|云效工程师指北

阿里云云效

云计算 maven 阿里云 java 并发 构建工具

恒源云(Gpushare)_如何防止训练不中断?技巧大放送1!

恒源云

算法 服务器 训练

企业实施知识管理的建议

小炮

企业知识管理

大数据培训-如何连通 Hive 数仓和ClickHouse

@零度

大数据 hive Clickhouse Seatunnel

轻盈潇洒卓然不群,敏捷编辑器Sublime text 4中文配置Python3开发运行代码环境(Win11+M1 mac)

刘悦的技术博客

Python ide 编辑器 Python3 Sublime

博文推荐|深入解析 BookKeeper 多副本协议(一)

Apache Pulsar

开源 云原生 中间件 bookKeeper Apache Pulsar

TiFlash 开源了

PingCAP

Kubernetes官方java客户端之三:外部应用

程序员欣宸

Kubernetes java client

We are learning by contributing!访 StarRocks Committer 周康、冯浩桉

StarRocks

数据库 开发者社区 StarRocks

在 AWS 上运行 CAE 工作负载的五个原因。

亚马逊云科技 (Amazon Web Services)

产品 计算机

DevEco Device Tool 3.0 Release新版本发布,支持多人共享开发、源码级调试

HarmonyOS开发者

HarmonyOS DevEco Device Tool

【直播回顾】OpenHarmony知识赋能第四期第四课——音频驱动开发

OpenHarmony开发者

OpenHarmony HDF框架 音频驱动开发

10年资深架构师分享 | 普通程序员向架构师进阶之路

云智慧AIOps社区

程序员人生 高薪 架构师 技术分享 职场发展

模块二作业

HZ

架构实战营 「架构实战营」

设备资产管理系统解决方案

低代码小观

资产管理 CRM系统 企业设备管理 设备巡检管理系统 企业管理软件

直播预告 | 如何在有限数据下实现资讯类网站海量信息自动分类

百度开发者中心

Linux下网络编程-UDP协议探测在线好友

DS小龙哥

4月月更

对话LigaAI创始人周然:在研发SaaS赛道,「颠覆」Jira | PLG十人谈

LigaAI

SaaS LigaAI 研发协作平台

web前端培训-检测Javascript类型的4种方式

@零度

JavaScript 前端开发

清华自研时间序列数据库Apache IoTDB原理解析

云智慧AIOps社区

数据库 时序数据库 消息队列 智能运维

架构标准TOGAF实践最重要的三件事

博文视点Broadview

阿里云:已有10000家企业在云上构建数据湖

Apache Flink

云计算 阿里云 数据湖 云原生

教你VUE中的filters过滤器2种用法

CRMEB

【直播回顾】OpenHarmony 知识赋能第四期第四课——音频驱动开发

Anna

OpenHarmony

Java培训-实现定时任务的几种方式

@零度

Java

开发者手册之如何成为 OceanBase Contributor

OceanBase 数据库

oceanbase OceanBase 开源 OceanBase 社区版

用现代Java调整经典设计模式_语言 & 开发_Olimpiu Pop_InfoQ精选文章