namelosw
2020-10-15 21:38:25 +08:00
其实你理解的没错,a.f(p1, p2)本质上和 f(A, p1, p2)区别没有那么大。
但是有个区别,有了对象(不一定非得有类),你可以写出:
def f(o):
o.printSelf()
那么这个 o 是什么呢? o 既不是 A,也不是 B,它是可以 printSelf()的东西。
总得来说,几个 implication:
1. 面向对象不一定有类
2. 面向对象的主要效果是实现多态
3. 抽象不一定需要类,函数就可以。而且继承往往是万恶之源,可读性和扩展性反而经常没有编写良好的函数好。即便是组合也是正确使用的函数组合性更强。
4. 多态不一定非得面向对象,也有模式匹配之类的方式
5. 面向对象的好处是添加新类型容易,比如有 A B 新增 C 容易,添加新的操作难,加个新方法 foo()就要把每个类型改一遍
6. 以如下的形式使用函数会把 5 的优缺点反转过来:
def foo(o):
if o.type is A:
doThis()
if o.type is B:
doThat()
这样的好处是新加一个操作 bar()函数就很容易,但是新加一个类型 C 就要把所有的函数改一遍
7. 面向对象常见的设计模式 Visitor,就是在面向对象范畴内,将 5 的优缺点反转成 6,即加操作容易,加类型难。在语言没有很好的函数支持的情况下使用 Visitor 是可以理解的,比如老版的 Java,像在 Python 或者 JavaScript 这种函数比较好用的语言里使用 Visitor 是自讨苦吃并且对设计模式没有深入理解的行为
8. 5 和 6 的优缺点的 trade off 可以用一个叫做表达式问题(expression problem)的问题概括,典型的解决方案是 Haskell 的 type class,还有一些奇怪且难懂的解法比如 object algebra 。
9. 还有更多的 implication 过于深入,就不展开了……
PS:大家说的和我上面说的面向对象都是非正统面向对象,即 Simula / C++ / Java / Python 等等,即有关类+封装 /继承 /多态的面向对象。其实应该叫面向类才对。
正统的面向对象核心是对象和消息传递,比如 Smalltalk 和 Erlang(你没看错)。