Redian新闻
>
使用现代Java调整经典设计模式

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

公众号新闻

作者 | Olimpiu Pop
译者 | 明知山
策划 | 丁晓昀  

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 中添加的)是 continue 和 break 语句的等效函数,第一个只接受数值限制参数,而第二个可以接受表达式。

尽管 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 才是它们当中的黑手党。

多模式(创建模式)、框架(Spring、Guice)是为了解决 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/

声明:本文为InfoQ翻译,未经许可禁止转载。

今日好文推荐

中国开发者整体规模 2016.37万,企业服务成为热门“移民”行业| InfoQ《开发者画像洞察研究报告 2022》发布

让小型企业提高 20 倍效率的统一技术栈

60 岁周星驰招聘 Web3.0 人才,要求“宅心仁厚”;马斯克计划裁掉推特 75% 的员工;Linus 致开发者:不要再熬夜了 | Q 资讯

可能是最严重的云存储数据外泄事故之一:微软承认服务器错误配置导致全球客户数据泄露

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
全新设计,来自德国IF红点设计获奖设计团队倾心之作:全触大屏通话智能手表重大信号:我囯将彻底调整经济布局!消费日报 |红布林、卡仕隆等融资;京东零售组织架构调整;快手调整商业生态委员会分工放开,不是由困难模式切换到岁月静好,而是切换到另一种困难模式!从负载均衡到路由,微服务应用现场一键到位聊一聊分布式锁的设计模型为全面建设社会主义现代化国家而团结奋斗——从党的二十大看以中国式现代化全面推进中华民族伟大复兴【炜炜道来】当下调整的主因和技术看调整空间【远见豪宅赏析】Medford 现代设计开放空间豪宅PICO官宣9月22日海外新品发布会;三星手机的趣味模式AR滤镜功能已被使用超过25亿次期待值++!上海乐高乐园概念设计模型首次公布大厂面试必问的设计模式,看这一篇就够了香港故宫文化博物馆:用现代手法演绎传统建筑美学“聪明反被聪明误”美华人老板用现金付员工薪水逃税,被罚近10万。新作速览丨乡土住宅新模式: 渭南·巴邑村玻璃砖房 / 西建大设计研究总院中央美术学院设计学院创新设计教研室主任程书馨:“创新几何”作为创新设计的一个基本框架华裔日餐老板用现金被国税局盯上 判3年和罚款$92,093美元餐馆华人老板用现金付员工薪水逃税, 被罚近10万设计模式最佳实践探索—策略模式【万歌诗词】卷四、自由诗破解品类困局,这匹SLG大黑马想用现实启明未来【报告】制造业企业物流“智”动化——驱动现代制造新模式的落地体系不栓塞|甲子光年智库闲话人生(206)老关庙小学和首义路小学乔布斯最经典的6句话,改变你的认知模式新作速览丨历史与现代:颂艺术中心 / TEMP 建筑设计工作室如何利用现代化数据栈高效处理地理信息数据老海归和白卷英雄鹤岗市调整部分区域风险等级,调整后全市无中高风险地区童话的窗口凡得流程海广跃:数字化转型=业务互联+(客户价值创造+商业模式创新+公司战略调整) | 数智前瞻·数智化十问在 Linux 中使用 Etcher 创建可启动 USB – 下载和使用指南 | Linux 中国厕哢佗洛基,试释屎诗事黑龙江一地调整部分区域风险等级,调整后全市无中高风险区域我如何使用现场 USB 设备恢复我的 Linux 系统 | Linux 中国柯布西耶的「昌迪加尔规划」:现代主义城市设计的得与失
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。