V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
index90
V2EX  ›  Go 编程语言

Go 的编程思想是什么?

  index90 · 2019-03-07 11:08:13 +08:00 · 12998 次点击
这是一个创建于 2089 天前的主题,其中的信息可能已经有所发展或是发生改变。

一直 OOP,换到 Go 也是用 OOP 思想,但总感觉很别扭啊。 有没有什么指引?

第 1 条附言  ·  2019-03-07 18:30:12 +08:00
补充一下为什么我要考虑编程思想。
如果是在面向业务的开发场景下,的确就是“能跑就行”,“就是干”。在微服务开发的领域里面,Go 的确十分简单。
但如果是需要实现通用 Agent,实现微服务框架等一系列通用型软件的话,这些软件是需要通过设计,再到实现的。目前能用来做设计的工具,我知道有 UML,而 UML 我只知道用 OOP 的思想来做设计。那么软件就得按照 OOP 来写了。

或者有没有适合 Golang 这种风格的设计工具?这应该也能解决问题。

其实我有个大胆的猜想,如果 Go 的性能相对于 PHP,Java 来说优势不大,或者根本没有优势。Go 这样的不明的编程风格,今天还会有人因为它的“简洁”而使用它么?
第 2 条附言  ·  2019-03-08 11:03:03 +08:00

如果大家对这个话题感兴趣,建议看一下38楼的回复。

看完后,我理解的关键点:

  1. 我一直认识的OOP是扭曲过的,OOP逐渐变成了“面向类编程”
  2. 有一个实用的建议,面向对象设计从对象活动图入手,而不是从类图入手
  3. 回归本源,抛开一切大学时所学的学术思想,从工程实际问题中,重新学习编程

再次感谢大家的热心讨论。

94 条回复    2019-03-09 09:26:24 +08:00
tt67wq
    1
tt67wq  
   2019-03-07 11:10:23 +08:00
能跑就得了,你还要啥自行车啊?
JohnSmith
    2
JohnSmith  
   2019-03-07 11:11:03 +08:00   ❤️ 1
组合模式+interface 解耦
Yoock
    3
Yoock  
   2019-03-07 11:11:33 +08:00 via iPhone   ❤️ 2
多看下 go 的标准库,编程思想就是 c 语言
chenset
    4
chenset  
   2019-03-07 11:11:54 +08:00
最好的指引: 撸个项目就是干, 干完就上手了 .
SuperMild
    5
SuperMild  
   2019-03-07 11:13:15 +08:00
大多数情况下 interface 比 OOP 好用很多。
FrailLove
    6
FrailLove  
   2019-03-07 11:15:03 +08:00   ❤️ 2
Do not communicate by sharing memory,instead, share memory by communicating.
zichen
    7
zichen  
   2019-03-07 11:23:55 +08:00
看看 unix 环境高级编程就有灵感了。
janxin
    8
janxin  
   2019-03-07 11:29:13 +08:00
Yuicon
    9
Yuicon  
   2019-03-07 11:32:08 +08:00   ❤️ 9
我先去掉一些东西 变得简单又优雅 然后后面再加回来
sunny352787
    10
sunny352787  
   2019-03-07 11:34:36 +08:00
当 C 写
wweir
    11
wweir  
   2019-03-07 11:45:43 +08:00   ❤️ 2
之前专门探讨过这个问题,我的理解是:go 不需要设计模式,不是没有,而是根本不需要!

想想为什么要设计模式?相信写个普通的 hello world 的话,没人会去套设计模式。在开发大型应用时,设计模式才能体现出它真正的价值。
那么,go 真的需要写成大型应用吗?目前大多数场景的做法是直接做服务拆分,各服务间通过网络来通信。

golang 目前重型应用有一些,大型应用还真不好找。除去第三方包,如果有二十万行以上代码的 golang 项目,欢迎分享一下。
server
    12
server  
   2019-03-07 11:46:25 +08:00
实用
wweir
    13
wweir  
   2019-03-07 11:48:04 +08:00
@wweir 重型应用 => 中型应用
releaseme
    14
releaseme  
   2019-03-07 12:06:08 +08:00
@tt67wq 又不是不能用,2333
12101111
    15
12101111  
   2019-03-07 12:10:40 +08:00 via Android
思想是 plan9,当然研究这个超前而又过时的操作系统没有什么意义。
gowk
    16
gowk  
   2019-03-07 12:25:25 +08:00
@chenset +1 就是干
azh7138m
    17
azh7138m  
   2019-03-07 12:29:02 +08:00   ❤️ 1
@wweir 很多啊,比如 https://github.com/docker/engine 再比如 k8s,刚才统计了一下,远超 20w
blless
    18
blless  
   2019-03-07 12:38:46 +08:00 via Android
awesome go
abmin521
    19
abmin521  
   2019-03-07 12:53:25 +08:00
@12101111 #15 distributed operating system ? 再讲一下?
rayhy
    20
rayhy  
   2019-03-07 13:01:36 +08:00
Golang 没有太注重设计模式,但是它的文档已经把你想要的说清楚了: https://golang.org/doc/
这里面几个链接最好都看一下,尤其是 https://golang.org/doc/effective_go.html
然后就是前几楼说的看代码了。
aimiyooo
    21
aimiyooo  
   2019-03-07 13:26:05 +08:00
少即是多
shihty5
    22
shihty5  
   2019-03-07 13:26:45 +08:00
Kotlin 的编程思想呢
cholerae
    23
cholerae  
   2019-03-07 13:32:02 +08:00
为啥总要纠结编程思想这种东西,oop 就 oop 呗
linxl
    24
linxl  
   2019-03-07 13:38:07 +08:00
总觉得 go 的继承看着一点都不直观. 好难受啊. 各种组合.
wweir
    25
wweir  
   2019-03-07 13:46:36 +08:00
@azh7138m 未必哦,把杂七杂八的非代码部分都扣除,再看看有单项目超过二十万行的吗?
lcode
    26
lcode  
   2019-03-07 13:49:54 +08:00
怎么没有...
你不需要!
maipian
    27
maipian  
   2019-03-07 13:51:46 +08:00
没有编程思想,不服就是干~
maxmin
    28
maxmin  
   2019-03-07 14:09:34 +08:00
用通信来实现内存共享,而不是内容共享来通信
azh7138m
    29
azh7138m  
   2019-03-07 14:10:56 +08:00   ❤️ 1
@wweir 有。
https://paste.ubuntu.com/p/25cRrtHDNh/

亲,cloc 在大部分包管理里面都有哦,这边建议您自己装一个看看呢 :)
wweir
    30
wweir  
   2019-03-07 14:13:28 +08:00
@wweir 统计了一下 engine repo,去除 vendor 目录,去除测试代码,总共 138147 行。这还是吧 daemon、client 等多个子项目合并在一起的项目。
使用命令:
find . -name '*.go' | grep -v '_test.go' | xargs wc -l
azh7138m
    31
azh7138m  
   2019-03-07 14:42:52 +08:00
@wweir
k8s 的,https://paste.ubuntu.com/p/TcD8QsHvQg/

亲,客服坐席忙,建议您自己先看一下呢 :)
kwanCCC
    32
kwanCCC  
   2019-03-07 15:44:54 +08:00
fire in the hole
================
go go go , fire in the hole
wweir
    33
wweir  
   2019-03-07 16:29:32 +08:00
@azh7138m 423884
kubernetes 这个 repo 已经远远超出单体应用的范畴了,里面杂糅了 kubelet、kubectl 等一系列单体软件,讨论这个项目的意义不大。
index90
    34
index90  
OP
   2019-03-07 18:30:33 +08:00
Append 了一下
hilbertz
    35
hilbertz  
   2019-03-07 18:31:04 +08:00
转为工厂流水线工人设计的语言
mauve
    36
mauve  
   2019-03-07 19:06:40 +08:00 via Android
面向接口编程 Interface oriented programming
GeruzoniAnsasu
    37
GeruzoniAnsasu  
   2019-03-07 19:58:45 +08:00
#35 + 1

golang 是个纯粹的为流水线工人设计的不会埋深坑不存在奇技淫巧谁都能写的语言

感觉好的实践真的就是尽量做成相互独立的微服务,然后 rpc 什么的随你
abcbuzhiming
    38
abcbuzhiming  
   2019-03-07 20:28:46 +08:00   ❤️ 43
我来谈谈历史好了
大多数人所谓的 OOP,其实都是说的“继承封装多态”这一套,但是,最早的 OOP,叫对象范式,对象范式的两个基本观念:
*.程序是由对象组成的;
*.对象之间互相发送消息,协作完成任务
请问,有“继承封装多态”的定义吗?没有!!!这两个观念与后来我们熟知的面向对象三要素“封装、继承、多态”根本不在一个层面上。倒是与再后来的“组件、接口”神合。

世界上第一个面向对象语言是 Simula-67,第二个面向对象语言是 Smalltalk-71。Smalltalk 受到了 Simula-67 的启发,基本出发点相同,但也有重大的不同。先说相同之处,Simula 和 Smalltalk 都秉承上述对象范式的两个基本观念,为了方便对象的构造,也都引入了类、继承等概念。也就是说,类、继承这些机制是为了实现对象范式原则而构造出来的第二位的、工具性的机制。而 Simula 和 Smalltalk 最重大的不同,就是 Simula 用方法调用的方式向对象发送消息,而 Smalltalk 构造了更灵活和更纯粹的消息发送机制。

到了 1980 年代,C++出现了。Bjarne Stroustrup 在博士期间深入研究过 Simula,非常欣赏其思想,于是就在 C 语言语法的基础之上,几乎把 Simula 的思想照搬过来,形成了最初的 C++。C++问世以之初,主要用于解决规模稍大的传统类型的编程问题,迅速取得了巨大的成功,也证明了对象范式本身所具有的威力。

大约在同期,Brad Cox 根据 Smalltalk 的思想设计了 Objective-C,可是由于其语法怪异,没有流行起来。只有 Steve Jobs 这种具有禅宗美学鉴赏力的世外高人,把它奉为瑰宝,与 1988 年连锅把 Objective-C 的团队和产品一口气买了下来

形势使然,C++的广泛使用,大大的影响了学术界,学术界疯狂的热爱继承这套体系,希望利用继承来描述世间的真实类别系统,然而现实世界复杂多了,蝙蝠是鸟也是兽,水上飞机能飞也能游,它们该如何归类呢。这套继承体制遇到真实世界的时候破绽很大,但是学界已经刹不住车了,甚至搞出了多重继承。这股风潮影响了后续的 Java (虽然它没“继承”那套翔一样的多继承机制,引入了接口这个其实更接近 OOP 本质的东西),扭曲了人们对面向对象的理解。既然必须要先知道对象的类型,才能向对象发消息,那么“类”这个概念就特别重要了,而对象只不过是类这个模子里造出来的东西,反而不重要。渐渐的,“面向对象编程”变成了“面向类编程”,“面向类编程”变成了“构造类继承树”。放在眼前的鲜活的对象活动不重要了,反而是其背后的静态类型系统成为关键。“封装、继承”这些第二等的特性,喧宾夺主,俨然成了面向对象的要素。每个程序员似乎都要先成为领域专家,然后成为领域分类学专家,然后构造一个完整的继承树,然后才能 new 出对象,让程序跑起来。

到了 1990 年代中期,问题已经十分明显。UML 中有一个对象活动图,其描述的就是运行时对象之间相互传递消息的模型。1994 年 Robert C. Martin 在《 Object-Oriented C++ Design Using Booch Method 》中,曾建议面向对象设计从对象活动图入手,而不是从类图入手。而 1995 年出版的经典作品《 Design Patterns 》中,建议优先考虑组合而不是继承,这也是尽人皆知的事情。这些迹象表明,在那个时候,面向对象社区里的思想领袖们,已经意识到“面向类的设计”并不好用。只可惜他们的革命精神还不够,delphi 之父在创建.net 的时候,曾经不想要继承,在微软内部引起了很大的争议,最后是向市场低头,加上了继承。

2000 年后,工程界明确的提出:“组合比继承重要,而且更灵活”,Go 语言也许是第一个明确的对这种思路进行回应的语言,你认为 Go 不够 OOP,那是因为你观点里的 OOP 其实是被扭曲过的,时至今日,学术界仍然很关注继承,但是工程界的思路已经变了,OOP 本质是为了职责分离而设计的范式,核心的东西是对象,不一定需要类,OOP 也不是继承封装多态的代名词
yippees
    39
yippees  
   2019-03-07 21:10:21 +08:00
c++ c#可以多继承,算变相组合了?
没明白 java 必须单继承
SuperMild
    40
SuperMild  
   2019-03-07 21:18:22 +08:00
@abcbuzhiming 补充一下,Rust 也不约而同地抛弃了继承,采用组合。
zjsxwc
    41
zjsxwc  
   2019-03-07 21:29:08 +08:00 via Android
我的体会是 go 可以 oop,它的结构 struct 有方法 method 与数据成员,也有 interface,于是就可以依赖注入,于是就可以处理业务复杂的项目。
abcbuzhiming
    42
abcbuzhiming  
   2019-03-07 21:40:44 +08:00
@yippees C#和 Java 一样的,不能多继承,多继承不是什么好设计
cuebyte
    43
cuebyte  
   2019-03-07 21:45:52 +08:00
Go 就是有 GC 的 C 啊,不會組織項目只能說明還需要學習。
MadbookPro
    44
MadbookPro  
   2019-03-07 22:01:06 +08:00
@Yuicon #9 赞成,比如说 Context
yippees
    45
yippees  
   2019-03-07 22:18:14 +08:00
@abcbuzhiming 是的,记错了。c#不能多继承。
blless
    46
blless  
   2019-03-07 22:18:42 +08:00   ❤️ 2
就没人说 Go 工程管理远比其他语言便利吗?
一门语言语法根本不能说明什么,说点其他的,写个完整项目需要啥。
首先,得有代码规范,其他语言的代码规范要么宽泛,要么约定俗成。真的要实际应用还得依赖各种第三方库,形成最佳实践。go 代码规范不说,连方法大小写,括号,缩进都规定了,工具链还自带 go vet,go fmt。其他语言要做到这样起码要有个资深项目经理,或者老程序员。直接上 go,我说省下半个项目经理不过分吧?
第二,代码仓库。go mod/go get/go list 就不说了,自带包管理,很多主流语言还是要插件才可以的。特意说一下代码仓库代码仓库,java maven, python pip,node npm,C# nuget...官方仓库当然好用,但是团队合作如果要发布到自己的代码仓库,go 绝对是最省事的,直接部署一套 git 就搞定了。这个特性加上跨平台静态编译,省掉几个运维不夸张吧?
第三,集成测试。go test /benchmark,go tool cover。不多说了,项目稳定性,健壮性基本都是靠测试用例堆起来的。
第四,debug。go pprof,trace。自带不多说了,目前已经自带火焰图了。
第五,文档。go doc。大项目必备。
大概就是这么回事,一条龙服务。其他语言目前这么完备的还没看到,rust 好像有几条已经差不多了。我反正这么用起来还是挺舒服的。
SuperMild
    47
SuperMild  
   2019-03-07 22:41:47 +08:00
@blless Go 的工具链确实优秀,而且是语言初期就官方介入,实用性强。
azh7138m
    48
azh7138m  
   2019-03-07 22:55:48 +08:00 via Android
@blless 不得,大部分 js 的保管理器,是支持从 git 安装依赖的,你看到 npm 这种也是支持的
ryanking8215
    49
ryanking8215  
   2019-03-07 23:13:28 +08:00
go 的 OOP,特性不多,但是基本够用。
封装:可以自定义 struct 封装数据,使用 struct 接收者的函数封装行为,类似于 class
继承:使用 mixin 的方式达到类似继承的方法
多态:使用 interface

go 的设计模式:不像有的语言库,支持单例模式或者基于委托的观察者模式,go 没有,需要自己撸,但是有了 OOP 的基本特性,也是可以实现的。另外 go 的函数是 first class, 可以适当的使用 FP 的方式简化一些设计模式的实现,例如工厂模式等。

go 的程序架构:MVC,ddd/clean architecture 都适用。
blless
    50
blless  
   2019-03-07 23:19:45 +08:00
@azh7138m 包管理想了想确实也不算太大优势,整套工具链整合才算优势吧。
azh7138m
    51
azh7138m  
   2019-03-07 23:32:03 +08:00 via Android
@blless 我觉得不行,go 在 1.11 之前,我一个依赖,本地不存一份,就意味着,一旦他更新了,我就血崩,没有版本管理,很尴尬。还有一个项目里面可能依赖一个包多个版本的情况,也会很难处理。
go 在这些事情上提供很少的操作空间,大部分时候确实换取了开发效率的提高,可是项目一旦大起来,依赖多起来之后要怎么办呢?
rust 比 go 不知高到哪里去,cargo rustup 用起来多方便,我要安装多个 go 还不是要自己切一下目录,多尴尬啊。
huiyifyj
    52
huiyifyj  
   2019-03-07 23:40:17 +08:00
@azh7138m #51
同意,go 的包管理真的无法接受。
blless
    53
blless  
   2019-03-07 23:49:41 +08:00
@azh7138m 本地固化依赖也是正常操作吧,我们项目基本上外部包应该都是封装过后再用的。直接引入业务这样就直接耦合了,所以多个依赖 /多个版本这种操作都是可以通过项目结构封装避免的,其他语言同样也会遇到这种问题的,相对来说 Go 语言提供的接口反而比别的语言更容易封装跟解耦。
rust 我只是粗粗看了下,还没有深入,没法讨论。不过多版本兼容,多个 go 我记得也是有的,go get 就可以直接升级。跨版本兼容的时候也可以用 // +build 条件编译限定不同 go 版本。我觉得大部分场景是够用的
feather12315
    54
feather12315  
   2019-03-07 23:55:50 +08:00 via Android
@azh7138m #51 我学过俩周的 rust,写了一个 tun/tap 捕捉 /转发网络流量的小程序。讲道理,我觉得 rust 就不是给新手用的语言,从根本上决定了它不可能如 go 一样流行。而 go 的版本管理…狗屎
scnace
    55
scnace  
   2019-03-08 00:16:52 +08:00 via Android
@azh7138m 从没有依赖版本管理 到 vendor 再到 dep 再到 现在官方强推的 mod 以及新出的 Go Team 自己托管的 go sum 验证中心 Go 不是在慢慢变得成熟吗?没有人是生来就是完美的啊 :/ (如果你是要跟风带 Rust 节奏 就当看不见我就好了
gowk
    56
gowk  
   2019-03-08 08:37:59 +08:00
@abcbuzhiming 感谢这么详细的介绍,我不太明白什么是对象范式,能不能举个实例介绍一下什么是对象范式,为什么对象范式比现在的面向类的设计好用?
wweir
    57
wweir  
   2019-03-08 09:48:36 +08:00 via Android
@abcbuzhiming 单冲这段介绍,必须 follow 一下。
半年前专门思考了 golang 的封装、描述世界的方式两三个月。
当时的结论是 golang 的 interface 方式描述世界的能力远继承的方式,唯一的缺点是业界对其使用方式的思考还比较欠缺。很多时候还是从继承的角度来进行封装,距离最佳实践的距离还很远。
所以看起来像是 golang 描述世界的能力很欠缺,实现不了大型应用。估计再过几年、十几年,大家(真正写业务的普通程序员)的认知够了,周边工具也完善了,也就能拿 golang 写大型单体服务了
thuai
    58
thuai  
   2019-03-08 10:07:34 +08:00
@wweir dragonboat 不知道有没有二十万代码
wweir
    59
wweir  
   2019-03-08 10:15:19 +08:00 via Android
@azh7138m @blless
golang 在 1.11 之后,包管理这一块依然很欠缺。而且,欠缺的不是工具,而是生态,以下这几个问题是日常踩坑:
1. 没有中心化的包下载仓库,网络、删除方面容易出问题
2. 没有中心化管理,导致大量仓库质量鱼龙混杂
3. 前些年没强调版本管理,导致大量包压根没有版本
4. 部分流行的包版本管理不规范,如:开个 v0.0.1 的版本,之后一两年年不发新版本

关于这些东西,之前专门写了个文章来进行分析:
https://wweir.cc/post/golang-%E9%A1%B9%E7%9B%AE%E7%BB%84%E7%BB%87%E5%BD%A2%E5%BC%8F%E7%9A%84%E6%BC%94%E8%BF%9B/
wweir
    60
wweir  
   2019-03-08 10:21:34 +08:00
@thuai dragonboat:62979 行,同样去除非代码部分和测试代码。

PS: 之前看过几篇 paxos、raft 相关的论文,一直想看一看 dragonboat 源码的。
ChristopherWu
    61
ChristopherWu  
   2019-03-08 10:27:53 +08:00
go 的编程思想是 : `if va, err = Myfunc(); err != nil ` 对所有的错误进行检查,那么你的程序就是无懈可击的对啦,try catch 就是垃圾 🐶🐶 /doge
specita
    62
specita  
   2019-03-08 10:37:18 +08:00
之前看过一篇博客说到了 java 和 go 在编程思想上的差别会导致两者代码在处理相同问题上的不同思路,记得主要就是说并发处理方面基于通信和基于内存差别?写了一年 go 又滚回来写 java 了,orz~~
index90
    63
index90  
OP
   2019-03-08 10:38:05 +08:00
@abcbuzhiming 茅塞顿开,感谢。看来需要回归本源,重新学习编程
index90
    64
index90  
OP
   2019-03-08 10:40:28 +08:00
@specita 是哪篇文章,烦请分享一下链接
Linxing
    65
Linxing  
   2019-03-08 10:57:23 +08:00
如果还是 OOP 的思想 写起来很难受的 毕业之后除了 Java 就基本没写过 OOP 的东西了 都是面向接口
gxm44
    66
gxm44  
   2019-03-08 11:08:26 +08:00
@wweir 说的很中肯,包管理一直是 go 的痛点。
abcbuzhiming
    67
abcbuzhiming  
   2019-03-08 11:15:45 +08:00   ❤️ 17
@gowk

程序设计有一个范式( paradigm )问题。所谓范式,就是组织程序的基本思想,而这个基本思想,反映了程序设计者对程序的一个基本的哲学观,也就是说,他认为程序的本质是什么,他认为一个大的程序是由什么组成的。这和他对于现实世界的看法有关。显然,这样的看法不可能有很多种。编程作为一门行业,独立存在快 60 年了,但是所出现的范式不过三种——过程范式、函数范式、对象范式。其中函数范式与现实世界差距比较大——真的纯函数范式在目前的编程实践中其实很少有,绝大部分语言只是取了函数范式的一个子集,即可以把函数作为参数传递,不过这并不是函数范式的核心,在这里不多讨论,只谈一个历史趣闻,有兴趣的可以自行去进一步查资料:当年的大牛们认为,Haskell 是“美丽的,聪明的”设计,C 语言是“丑陋的,简陋的”设计,然而最后占据了世界主流的却是“丑陋的,简陋的”的设计。

而过程范式和对象范式可以视为对程序本质的两种根本不同的看法,而且能够分别在现实世界中找到相应的映射。

过程范式认为,程序是由一个又一个过程经过顺序、选择和循环的结构组合而成。反映在现实世界,过程范式体现了劳动分工之前“全能人”的工作特点——所有的事情都能干,所有的资源都是我的,只不过得具体的事情得一步步地来做。

对象范式则反映了劳动分工之后的团队协作的工作特点——每个人各有所长,各司其职,有各自的私有资源,工件和信息在人们之间彼此传递,最后完成工作。因此,对象范式也就形成了自己对程序的看法——程序是由一组对象组成,这些对象各有所能,通过消息传递实现协作。

对象范式与过程范式相比,有三个突出的优势,第一,由于实现了逻辑上的分工,降低了大规模程序的开发难度。第二,灵活性更好——若干对象在一起,可以灵活组合,可以以不同的方式协作,完成不同的任务,也可以灵活的替换和升级。第三,对象范式更加适应图形化、网络化、消息驱动的现代计算环境。

重复一遍对象范式的两个基本观念:

程序是由对象组成的;
对象之间互相发送消息,协作完成任务;

这就是对象范式的核心,并没有规定对象的标准,这里的对象只是一个抽象的概念,人为划定的,包含一定职责和功能的组件。对象之间互相“发消息”其实也只是一个抽象的概念,并没有规定“发消息”这一行为究竟该是什么样的,核心问题就在这里,这里埋下了一个大坑,为后来面向对象变成被扭曲成面向类编程留下了一个悬念。

历史没有假设,把 OOP 应用于编程语言实践并第一个“获得广泛成功”的语言是 C++,而上面说了,C++是基于 Simula 的思想,Simula 认为“发消息”是什么样的操作呢?向一个 Simula 对象中发送消息,就是调用这个对象的一个方法,或者称成员函数。那么你怎么知道能够在这个对象上调用这个成员函数呢?或者说,你怎么知道能够向这个对象发送某个消息呢?这就要求你必须确保这个对象具有合适的类型(方法),也就是说,你得先知道,哦这个对象是什么(类),才能向它发消息。而消息的实现方式被直接处理为成员函数调用,或虚函数调用。

而另外一边的 Smalltalk 在这一点上做了一个历史性的跨越,它实现了一个与目标对象无关的消息发送机制,不管那个对象是谁,也不管它是不是能正确的处理一个消息,作为发送消息的对象来说,可以毫无顾忌地抓住一个对象就发消息过去。接到消息的对象,要尝试理解这个消息,并最后调用自己的过程来处理消息。如果这个消息能被处理,那个对象自然会处理好,如果不能被处理,Smalltalk 系统会向消息的发送者回传一个 doesNotUnderstand 消息,予以通知。对象不用关心消息是如何传递给另一个对象的,传递过程被分离出来(而不是像 Simula 那样明确地被以成员函数调用的方式实现),可以是在内存中复制,也可以是进程间通讯。到了 Smalltalk-80 时,消息传递甚至可以跨越网络。所以各位,其实和消息队列类似的功能当年就已经存在了,消息队列 1 是为了解耦,2 是为了削峰错流,某种程度上消息队列不是实时的,然而 Smalltalk 的消息机制,某种程度上可以视为实时的。这也是它的先进性所在,我们希望解耦,但是我们不需要延迟。

很可惜,历史没有假设,Smalltalk 的直系继承者 Object-C 被 Steve Jobs 收入苹果公司,很长一段时间没有和公众见面。后来有一个也利用了该思想的专门为电信级通讯设计的语言 erlang,Actor 模式由它定义,其实就是那套消息机制,然而 erlang 是少见的纯函数式编程的语言,接受的人不多,也没流行开来。

后来就和大家知道的那样,因为 C++的流行,导致“类”这个概念变的无比重要,毕竟你要先知道对象的“类”,你才能确定,我能不能发消息给这个对象。于是类的概念变成了第一要素,OOP 至此被扭曲为 COP ( Class Oriented Programming,面向类程序设计)。

客观地说,“面向类的设计”并不是没有意义。来源于实践又高于实践的抽象和概念,往往能更有力地把握住现实世界的本质,比如 MVC 架构,就是这样的有力的抽象。但是这种抽象,应该是来源于长期最佳实践的总结和提高,而不是面对问题时主要的解决思路。过于强调这种抽象,无异于假定程序员各个都是哲学家,具有对现实世界准确而深刻的抽象能力,当然是不符合实际情况的。结果呢,刚学习面向对象没几天的程序员,对眼前鲜活的对象世界视而不见,一个个都煞有介事地去搞哲学冥想,企图越过现实世界,去抽象出其背后本质,当然败得很惨。

但是学术界一向高傲,传统上学术界一直都是理论定义的先驱,负有“指导众生”的义务,所以学术界仍然坚持这套基于类的 OOP 概念,但是工程界自从发现基于类的抽象其实对程序员的心智负担过高后,组合优于继承的思想就开始深入人心了。对象才是第一要素,对象并不依赖于类,对象的组合方式是彼此发消息,彼此发消息的方式也可以不依赖类,就算是传承自 C++的 Java 也搞出了接口这种方式——其实这种方式距离抛弃类就只有一步之遥了,我要知道对象有没有方法让我发消息,我检查接口定义就行了,我为啥需要类,Java 需要类来制造对象是历史惯性,不是必须。

历史让 C++走上了舞台,历史也终将让 COP 重新回到 OOP 的本来面目
gowk
    68
gowk  
   2019-03-08 12:39:44 +08:00 via Android
@abcbuzhiming 茅塞顿开,感谢回复。如果能有这方面的书推荐一下就更好了。
abcbuzhiming
    69
abcbuzhiming  
   2019-03-08 13:01:49 +08:00   ❤️ 1
@gowk 没有书可以推荐,因为绝大部分技术书籍基本不讲技术历史,其实我是个对技术历史脉络比技术本身还感兴趣的人,年轻时精力好,在那个博客发达的时代到处翻人家写的点滴记录,有了这么点积累而已。其实我也万分的想让别人给我推荐讲技术历史脉络的书籍,然而这类书真心罕见
passerbytiny
    70
passerbytiny  
   2019-03-08 13:03:36 +08:00
@abcbuzhiming #36 虽然你说的绝大部分都是对的,但你这一棍子打死类、继承的态度,跟你所批判的“面向类变成的态度”,有什么区别。

再看你接下来的描述,感觉你有这么一种思路:直接去做东西,不做或者后做模子,先做模子再按照模子做东西的都是 S13。
passerbytiny
    71
passerbytiny  
   2019-03-08 13:09:08 +08:00
@wweir #10 你这个“二十万行”的规格太离谱了。举个例子,一万行代码、没有设计模式的项目,1.0 版本你准备花多长时间评审和单元测试,1.0-1.1 版本准备花多长时间,1.21-2.0 版本又准备花多长时间。
shayuvpn0001
    72
shayuvpn0001  
   2019-03-08 13:28:57 +08:00 via iPhone
@abcbuzhiming 这几个长回复真心不错,解决了长久以来我对各种语言的来龙去脉的困惑。介绍硬件发展和软件公司发展的文章很多,语言这一块很少,而且大多都是围绕大家耳熟能详的几个语言的来龙去脉介绍,小众一点的几乎没看到过完整的介绍,今天算是看到了 the big picture。
zwpaper
    73
zwpaper  
   2019-03-08 13:39:31 +08:00 via iPhone
@abcbuzhiming 最后一段,组合比继承更重要,有参考的资料或者文章吗?想多了解一下

谢谢
dengtongcai
    74
dengtongcai  
   2019-03-08 13:59:43 +08:00
说下我的经验+愚见:设计->按设计编码->微调设计
abcbuzhiming
    75
abcbuzhiming  
   2019-03-08 14:01:55 +08:00
@passerbytiny 我没有一棍子打死类和继承,我只是强调类和继承不是 OOP 必须的而已。另外,基于哲学的抽象领域,类有很高的价值,这也是为啥类和继承这套体系在学术界仍然相当有地位的原因,但是绝大部分程序员,只是凡人,程序的本来目的,其实也是为了让大部分凡人能够利用计算机编程这一工具而已。曲太高,和就寡。我里面提到设计的更好的 Haskell 并没有被广而接受,而被设计的并不优秀的 C 语言成了历史的选择,就是例子
abcbuzhiming
    76
abcbuzhiming  
   2019-03-08 14:02:37 +08:00
@zwpaper 1995 年出版的经典作品《 Design Patterns 》中,建议优先考虑组合而不是继承
wweir
    77
wweir  
   2019-03-08 14:34:05 +08:00
@passerbytiny 是离谱的,对 go 而言,10 万行就已经是巨型的项目了,为了避免到处是杠精,才说的 20w 行。
就我自身而言,3、4 万行的代码还能 hold 住,再多的话,没优秀的封装、模块化,根本进行不下去。
bsg1992
    78
bsg1992  
   2019-03-08 14:46:39 +08:00
@blless 你说的那些除了 代码规范 go 是自带的,其他的.NET 都有 也不比你差啊。
wind3110991
    79
wind3110991  
   2019-03-08 14:54:22 +08:00
@wweir loraserver 感觉算是比较大的项目了,不过我一直觉得行数多少不是问题,主要是结构和思想够不够清晰和简洁
https://github.com/brocaar/loraserver
est
    80
est  
   2019-03-08 14:55:38 +08:00
golang 的思想就是 interface 一把梭。
passerbytiny
    81
passerbytiny  
   2019-03-08 16:09:57 +08:00
@abcbuzhiming #68 类不是你说的给高智商的人用的纯抽象的东西,类就是 OOP 的必须的基本的组成部分,你现在的观点就是在程序开发上一棍子打死“类”。

你的教条是对象范式的两个基本概念,然而我最早接触的 OOP 的目的可没有你那么高深的范式要求,就一个最简单的目的:像现实物体一样去看待程序。现实中有鸟、麻雀、小明家的麻雀,映射到程序中就是基类、子类、对象。在这里类、继承、封装都是直接从现实中抽取的东西,这才是凡人的东西,反而你的各种范式是曲高和寡的。

而且即使按照你的教条来看,类也没有违反那两个范式,程序只包含对象和对象之间的消息,那么类为什么不能是一种负责定义和生成其它对象的“对象”。

你在表述里极力的想将“类”描述成学术界专用的、用来做抽象的术语,然后极力的去鄙视学术界,然而学术界从来都是“在现实的基础上抽象,然后去解决现实”。你对哲学思想的理解也很有问题,哲学是“来自于现实和其它科学,并反过去帮助现实和其它科学”。你的种种表述让我想到了“数学无用”这个古老的词语

你的种种观点和表达手段,还让我想到了另一个词——民科,真没想到在无名无利的程序设计领域也能出现民科。
fox1955
    82
fox1955  
   2019-03-08 16:32:12 +08:00
oo 就是为了更好的解藕(可插拔)。一句话的事。
abcbuzhiming
    83
abcbuzhiming  
   2019-03-08 17:09:36 +08:00   ❤️ 1
@passerbytiny
你已经把“民科”的帽子扣在我头上了,你已经立于不败之地了,呵呵,你高兴就好
blless
    84
blless  
   2019-03-08 17:23:05 +08:00 via Android
@bsg1992 没说 C#不好,相反我接触 Go 之前最喜欢的就是 C#。C#的 linq lambda 都是我很喜欢用的东西。不过 c#封闭太久了,跟微软全家桶深度绑定,现在追赶醒悟过来追赶开源,也不知道会不会太晚。
index90
    85
index90  
OP
   2019-03-08 17:23:34 +08:00
@passerbytiny 程序是用来解决现实问题的。现实很复杂,计算机太简单,为了让计算机理解人的指令,人们发明了编程语言;为了让计算机能够理解人类的世界,人们发明了数据类型,数据结构。
计算机在最初是给数学家用的,那时候还没有软件工程师,即便到了今天,计算机还不能够直接解决现实问题,而软件工程师的最重要职责,就是把现实问题转化为数学模型,而编程只是最后的一步。

DDD,对象范式,是设计思想,用于帮助我们将复杂的现实问题向数学模型转化。
以 Java,C++为代表的 OOP,是实现手段,“封装,继承,多态”都是实现手段。面向接口编程都是实现的手段。

程序员习惯以技术实现手段来倒推分析世界,这也是为什么技术人员总是被喷技术性思维的根本原因。今天我提问的标题,也犯了同样的错误。

人的理解是有局限性的,受你所处的环境,你的经验影响。加入我只是小明家的猫,我从来没有离开过小明家,我只知道小明家的麻雀,我设计一个和小明家的麻雀沟通的工具,却不知道小明家以外还有其他的麻雀,说着不同的语言。这就是凡人的局限性。与其尝试超越自身极限,去想象自己根本没见过的抽象事物,不如静下心来,想想如何和面前的麻雀沟通。

类和继承是有价值的,但不是凡人现阶段必要的。实际工作中,也会体会到,在开发一个系统足够久后,回过头来才知道“正确”的设计是什么,但你又如何保证若干年后,回过头来,依然是“正确”的呢?对世界的认知和自身经验有关。不去纠结一个类如何设计,不代表类没有用,不代表放弃程序设计,而是更坦承地面对自己的无知,承认自己是个凡人,基于眼前的活生生的对象,做出当时最有把握认为最正确的设计。
skadi
    86
skadi  
   2019-03-08 17:25:53 +08:00
通信吧.
atonku
    87
atonku  
   2019-03-08 17:31:37 +08:00
让语言自己 go,自己编程自己
wysnylc
    88
wysnylc  
   2019-03-08 17:39:45 +08:00
面向对象设计,面向过程开发
dongya
    89
dongya  
   2019-03-08 18:46:36 +08:00
justfortest
    90
justfortest  
   2019-03-08 18:48:28 +08:00
@atonku #87 就该这样,一门成熟的语言,应该会自己编程
chenqh
    91
chenqh  
   2019-03-08 19:20:14 +08:00
难道不是 golang 围绕 go 程建立了一套生态?
dartabe
    92
dartabe  
   2019-03-09 06:02:52 +08:00
看完全篇的感觉就是 java 依然万金油无可替代。。。
ihipop
    93
ihipop  
   2019-03-09 09:10:59 +08:00 via Android
@blless 其他语言大部分都有包的版本🔒锁
richieboy
    94
richieboy  
   2019-03-09 09:26:24 +08:00
一直觉得"对象"这个翻译对于中文来说不能很好的表达"object"的涵义
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2741 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 32ms · UTC 10:11 · PVG 18:11 · LAX 02:11 · JFK 05:11
Developed with CodeLauncher
♥ Do have faith in what you're doing.