编程与软件工程quuxplusone.github.io
该用简单自由函数时却用 class 的问题
The use of `class` for things that should be simple free functions
2020 — 2022,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这篇博文讨论一个常见的设计反模式:把本应是简单自由函数的功能包装成类(例如只有构造方法和一个方法的类),并引用《The Elements of Programming Style》等经典来说明应优先使用简单函数。文章时隔两年两次登上 HN 首页,引发了关于何时该用类、何时该用函数的长期争论。
为什么经久不衰:过度封装是各语言中普遍存在的问题,而'类 vs 函数'的边界判断是常谈常新的设计基本功,文中观点和评论区正反两方的论证至今仍有参考价值。
HN 评论精选
有状态的类在增量搜索等场景下能提供自由函数做不到的能力,不能一概而论
反向观点:虽然很多情况下这种做法不对,但要认识到什么时候它是对的,因为两者看起来非常相似。以图搜索为例,BFS 或 Dijkstra 的典型实现是函数,但如果把 Dijkstra 做成类(比如带一个迭代节点的函数),就能做到函数难以实现的事:(a) 复用同一对象计算到多个顶点的距离,支持增量搜索;(b) 复制对象后在不同分支上继续搜索;(c) 保存/恢复搜索状态以暂停和续搜;(d) 在一个或多个图上同步进行多次搜索。不懂的人会觉得用类写 BFS 正是'OO 反模式',实际上它为更复杂的场景提供了显著的新功能。
dataflow查看英文原文
Counter-point: while in many situations this isn't the right approach, it's worth recognizing when this is the right approach, because they can look awfully similar. An example of this is graph searching, e.g. BFS or Dijkstra's algorithm. The typical implementation is a function. But if you make Dijkstra a class, with (say) a function to iterate through nodes, it lets you do several things that would be difficult with a function: (a) you can now re-use the same object for computing distances to multiple vertices, which allows incremental search, (b) you can now fork/copy the object and continue searching on different extensions of the original graph, (c) you can now save & restore the searcher state to pause the search & continue it later, (d) you can do multiple searches across one or more graphs in lockstep. IMHO these are very much not obvious, and to someone who doesn't recognize what's going on, a class for something like BFS will look exactly like an "OO antipattern", when in reality it's actually providing significant additional functionality for more complicated situations.
对象与闭包互为表里,这条经典寓言点出两者本质相通
大师 Qc Na 与学生 Anton 同行。Anton 问:'师父,听说对象是很好的东西,是真的吗?' Qc Na 怜悯地答:'愚徒——对象只是穷人的闭包。' Anton 潜心研读《Lambda: The Ultimate...》系列论文,用闭包实现了一个 Scheme 解释器,自认领悟,便对师父说:'我明白了,对象确实是穷人的闭包。' Qc Na 用戒尺打他:'你何时才能明白?闭包才是穷人的对象。' 那一刻 Anton 顿悟了。
AlexanderDhoore查看英文原文
The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures." Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress. On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
引用 Python 社区'别再写类了'的著名演讲佐证文章观点
这在 Python 里也有说法:'如果你的类只有两个方法,其中一个是 __init__,那它其实是个函数',出自演讲《Stop Writing Classes》。
makapuf查看英文原文
Also known in python as "if your class has only two methods, one of which is init, it's a function" in the "stop writing classes" https://www.youtube.com/watch?v=o9pEzgHorH0 EDIT: typo, changed link
单方法类可退化为闭包,类与函数的选择更多是风格与文化问题
如果你经常写返回多个闭包的函数,也许该考虑用类——这当然是反话,但反过来想很有用:只有一个方法的类大概可以变成闭包。更进一步,如果类只捕获一个东西且从不修改它,那它其实只是一组共享同一个首参数的函数,很多'Database'抽象就是如此。函数相对对象的缺点是调用方得给它起名字,而类名自带语义。这类问题往往是风格或团队文化问题,而非技术问题。写代码终究是一种设计练习。
gorgoiler查看英文原文
If you find yourself regularly writing functions that return more than one closure, you should consider using a class instead. That’s an ironic joke of course — who does this? — but it’s a helpful way to then think about the inverse. If you have a class with one function then it could probably just be a closure. Even better, if it closes one thing, one thing only, and uses that thing while never modifying it then your class is really just a group of functions all of which share the same first argument. Quite a lot of “Database” abstractions are like this, with methods built around a single internal reference to a database connection. The downside of returning a function instead of an object is your caller has to give it a name: lol = build_handle() lol() …versus the class-as-sensible-name-enforcement version: lol = Handle() lol.sensible_name() As always, quite a lot of these problems are stylistic (or cultural, if you work in a team) rather than technical. Coding is, amongst other things, an exercise in design.
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选