设计模式很烂

Lobsters Hottest 新闻

摘要

本文认为设计模式被高估了,它们常常是对语言局限性不必要的变通,以Java为主要例子,并与Scala等更具表现力的语言进行对比。

<p><a href="https://lobste.rs/s/7qssyu/design_patterns_suck">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/26 12:08

# 设计模式真糟糕 来源:https://luminousmen.com/post/design-patterns-suck/ 在软件工程中,"设计模式"这个词——说实话,这说法有点多余,难道*所有*模式不都是设计出来的吗?——被翻来覆去地提及。它最初来自建筑学——是*真正*的建筑学,有楼房和平面图那种——不是软件领域的。 但在1994年,软件界迎来了自己的版本,当时那本如今臭名昭著的《设计模式》由Gamma、Helm、Johnson和Vlissides出版,也就是所谓的"四人帮"(GoF)。他们引入了23种经典模式,作为比函数调用更高层次的抽象。这些模式被设计成与语言无关、可复用的模板,用于解决反复出现的软件设计问题。 听起来不错,对吧?简直好得有点过头了…… 问题在于,设计模式已经从有用的术语被捧成了某种教条。它们被当作普适的解决方案来教授,被应用在不需要的地方,还被视为优秀工程实践的标志。 现实是:**设计模式真糟糕。** 没错,我直接说了。 **设计模式被高估、被滥用,而且很多时候完全是多余的。** 这话可能听起来刺耳,尤其是对那些把《四人帮》放在床头的人,但请听我说完。大多数时候,设计模式不过是为我们编程语言不够强大、不够灵活来表达我们*真正*想要的东西而做的丑陋变通罢了。 ## Java 与样板代码的孽缘 就拿 Java 来说吧(今天我会频繁炮轰 Java,请坐稳)。我们从哪儿说起呢?Java 简直是"设计模式狂热"的代言人。每个项目看起来都像自己的复制品,因为 Java 开发者被教导要尽可能多地塞进各种模式。 正是这种语言几乎强行把设计模式推向了主流。为什么?因为 Java 啰嗦、僵硬、缺乏表现力。这就像写一部小说,却只允许使用三个音节的单词——每个问题都感觉比实际难十倍。 *哦,你在做一个简单的 CRUD 应用?*最好扔进去一个工厂模式,再加个观察者模式处理那个数据库变更通知,别忘了单例模式——因为,你懂的,我们都需要一个全局日志记录器,对吧? ## 模式 vs 语言特性 设计模式往往很糟糕的核心原因在于,它们大多数时候之所以存在,仅仅是因为*语言本身缺失某些能力*。你基本上是在为语言的局限性做变通。 拿单例模式来说。你肯定见过无数次: ```java public class Logger { private static Logger instance; private Logger() {} public static Logger getInstance() { if (instance == null) { instance = new Logger(); } return instance; } } ``` 这大概需要 15 行代码就为了说一句"我只想这个类只有一个实例"。我们是原始人吗?我们*不应该*需要手写这种东西。一门现代语言应该提供优雅处理这种需求的构造,但 Java 就是不行。相反,我们得到的是大量伪装的"最佳实践"里的样板代码和复杂性。 想看看 Scala 怎么处理的吗? ```scala object Logger ``` 就这些。整个单例模式搞定了。 不需要折腾静态块、线程安全或者懒加载那些破事。Scala 做到了 Java *本来就应该*做的事情:把这当作一个基本的语言特性,而不是需要手动强制实现的模式。Java 把你逼进这个烂摊子,因为它没有头等函数。你写策略模式,那是语言的问题,不是你的问题。 设计模式不是在解决你代码中的问题;它们是在解决语言的问题。 工厂模式?那只是 Java 拒绝提供合适的构造函数或原生处理复杂对象创建的方式。在 Python、Ruby 或 Scala 这类语言中,你很少需要工厂模式。实际上,Java 开发者津津乐道的大多数设计模式,在更灵活、更具表现力的语言中都会消失。 拿 Python 举例: - 需要工厂模式?直接传一个函数或者巧妙地用`__init__`。 - 想要单例?用一个模块或类初始化一次就行了。 - 观察者模式?函数是头等公民,直接到处传就行。 事实是,在足够有表现力的语言中,模式要么变得微不足道,要么更好的是——*它们压根就不存在*。你可以直接处理问题,而不是把它们包裹在别人 20 年前用一门已经过时的语言搞出来的抽象里。 ## 过度工程的邪教 设计模式也助长了软件世界一个更深层的问题:过度工程。我见过初级工程师(不幸的是,也有一些高级工程师)一听到"设计模式"就两眼放光,然后立马想把尽可能多的模式塞进自己的项目。 他们是在解决想象出来的问题。 一旦发生这种情况,代码库就会从能理解的东西变成不可读、脆弱、过度抽象的一团乱麻。它会变成接口、工厂方法和奇怪命名惯例的迷宫,让你觉得自己像是在解读古代文献。 "好的"设计模式往往容易被过度工程化,因为它们需要尽可能多地迎合各种用例。但过度工程化的代码是有代价的:你得阅读它,理解它的功能,还要理解它如何在整个软件系统的上下文里工作。因此,和任何其他软件开发技术一样,你必须评估该技术的使用成本,并判断收益是否大于成本。 不是每个问题都需要设计模式。实际上,大多数问题都不需要。通常最简单、最直接的解决方案就是正确的。一条经验法则:如果你的解决方案需要画个图才能解释清楚,那你就走过头了。 ## 模式真正有用之处 模式最诚实的价值:给一个大概念起个简短的名字。在团队里,说"那是个外观模式"比每次都解释为什么要把三个类藏在一个包装器后面要容易得多。 就这些。这才是真正的使用场景。 模式不是用来教你写出好代码的。它们是用来*谈论*已经写好的代码的。这样你可以问*"这个类是什么?"*然后听到*"哦,那是中介者的一部分。"*而不是疯狂地把你的代码和 UML 图对比,想着"我现在该用哪个模式?!" 一个理解底层概念——关注点分离、封装、组合优于继承——的开发者,自然能写出整洁的代码,哪怕他从未听说过"单例"这个词。模式只是为优秀开发者已经知道如何做的事情贴上的标签。 我在好几家最大的科技公司工作过。没人每天用这些术语,我在面试中也从未被问到过它们(如果被问到,那对我来说会是个危险信号)。 ## Gosling 哲学 vs Guido 哲学 DHH 有一段很棒的论述,点明了 Java 为什么会变成这样。 James Gosling,Java 的设计者,对程序员持悲观看法。他的前提:如果给普通开发者太多能力,他们必然会搬起石头砸自己的脚。所以 Java 被构建成一个沙盒——保持僵硬、保持安全、别让他们伤到自己。对于一家编写要维持 20 年代码的中等规模保险公司来说,这很棒。但对于表现力来说,就不那么好了。 Guido van Rossum 则走了相反的路。他的前提:代码被阅读的时间多于编写的时间,所以要优化清晰度,给程序员真正的工具。头等函数、装饰器、上下文管理器、鸭子类型——Python 给了你直接解决问题的构建块,而不是把一切都通过类层次结构和接口仪式来路由。 设计模式是 Gosling 世界里的解决方案。它们之所以存在,是因为语言不信任你直接解决问题。在 Guido 世界的语言里,你只管……解决问题就行了。 设计模式是语言不够有表现力时代的遗物。一半的 GoF 模式在 Python、Ruby 或 Scala 中消失的事实说明了一切——它们从来不是关于设计的。它们是关于语言不再碍你的事。

相似文章

编程依旧令人头疼

Hacker News Top

这篇文章批判了对科技职业浪漫化的看法,将其描述为混乱和充满压力而非井然有序,同时探讨了人们对人工智能取代岗位的焦虑,以及软件开发缺乏明确方向的问题。

迈向可理解的软件

Lobsters Hottest

本文批判了当前的编程实践和对大语言模型的依赖,反而主张通过更好的抽象、文档和软件栈来使代码更易于理解和维护。

优秀的架构不需要胡萝卜,也不需要大棒

Lobsters Hottest

这篇博客文章主张,良好的软件架构应当是不言自明且毫无阻力的,倡导采用 Netflix/Spotify 式的“铺平道路”模式,而非依赖强制性的治理委员会或嵌入式架构师。