如何透过现象看本质,真正理解“类”这个概念?

2020-10-15 14:51:51 +08:00
 Hlianbobo
最近看 python 的书,其中讲了一些关于面向对象和类的知识。我看了以后头脑当中产生很多困惑,在此写出来。还请各位老师点播。

我看后感觉类就是一个自定义函数包。例如自己定义一个函数包的名称叫 A,包里面包含了好几个方法(也就是函数) sin,cos,子类 B 里面包含了方法(函数) tan 。tan 的定义使用了类 A 中的方法 sin 和 cos 。tan=A.sin/A.cos

如果这就是类。那么我们直接定义几个全局变量 sin,cos,tan 。以后直接在程序中调用不就可以了?何必非要打包到 A 和 B 里面。以后再通过 A.sin A.cos 的方式调用呢?没有本质区别啊。看起来只是形式上不同。

不过反过来一想,我上面的理解肯定有有问题的。如果类仅仅是个自定义函数包。那么就不存在某语言是否支持类或某语言不支持类的问题了。喜欢使用类的程序员。直接自己定义一个全局变量叫做 A 。然后把 A 接收的参数传给内部的函数 sin 和 cos,不一样可以实现“类”的调用??哪有这种事。如果时这样 python 哪还有必要规定专门用 class 来定义类,用 def 来定义一个方法?
所以究竟什么是类。使用类相对于使用全局变量有什么区别?有什么优势?还请老师点播。
6724 次点击
所在节点    Python
76 条回复
zsdroid
2020-10-15 16:21:46 +08:00
A.sin A.cos 对外调用没问题啊。

但是你的实现呢?
sin 方法的实现写在哪??
charlie21
2020-10-15 16:21:49 +08:00
搜 subtyping
https://www.zhihu.com/question/265433666/answer/337599960
https://medium.com/@mattia512maldini/inheritance-is-not-subtyping-b84488eca5ea

如果我讲 OOP,我直接从 组合优于继承 开始讲,然后讲讲 traits,讲讲这篇文章,
https://stackoverflow.com/questions/9205083/traits-vs-interfaces/9205347#9205347
“In fact, creating traits that fulfill the capabilities required by an interface is the ideal use case.”

再讲讲什么叫底层依赖高层,完事了
https://www.zhihu.com/question/265433666/answer/337599960
“一个稳定易拓展的系统应该让底层依赖高层”

然后直接讲软件设计模式里的装饰器模式

-
关于 继承 inheritance
Neither is inheritance: as a code reuse tool it is widely recognized as useless and it is slowly being discarded. Just don’t use it and no harm will come.
-

然后讲 IoC,用 IoC 来接管依赖关系并生成我需要的类的实例

这样一种叙述方式可以避免 OOP 里关于父类子类这一叙述里带来的思维弯路。它是为人脑设计的障碍

clear contracts; using interfaces will force you to think in term of communication between objects;

thinking “communication first” will give your brain free resources by splitting its job in two steps: design time and implementation time; our brain doesn’t like to work on two different things at the same time, especially switching continuously between the two;

https://codeburst.io/inheritance-is-evil-stop-using-it-6c4f1caf5117
-
clf
2020-10-15 16:24:45 +08:00
面向对象的类,可以理解为“类别”这种概念。我们概括一个类别往往是提取这些东西的共性。我们以类进行分析,就是我们对这些共性进行分析。

比如学生 ABCD,他们都有名字、学号、身份证、照片、年龄等各种属性(行为),当然个别人可能有一些个性的属性(行为),但对于学生这个身份来说这些额外的个性的东西是没有用的。

系统里对这些共性进行总结形成了 Student 类,我们通过 Student 类去概况一个 学生 该有的属性和行为。
ruyu
2020-10-15 16:28:11 +08:00
面向对象是个好东西, 但是不要被面向对象禁锢了思想.
nutting
2020-10-15 16:28:50 +08:00
全局变量是面向过程的思维,类在程序运行时的体现是对象,如果你就一个对象,那和全局没啥区别。要是一个类产生多个对象呢,要互相独立的。
charlie21
2020-10-15 16:32:36 +08:00
所谓的 “以后直接在程序中调用不就可以了?何必非要打包到 A 和 B 里面。以后再通过 A.sin A.cos 的方式调用呢?没有本质区别啊。看起来只是形式上不同”

回答你的疑问:有一些时候,用函数是 OK 的没问题的;没有副作用的函数叫做纯函数。
关于纯函数的用处,参考 纯函数为什么能消除副作用
blog.leapoahead.com/2015/09/19/function-as-first-class-citizen/

有一些时候,你会乐意为副作用买单:让实例去做函数的事(让纯函数不纯了)因为实例是可以实例化(初始化)的,它可以维护一些自己的状态(实例变量)。函数没有实例变量,这就是状态,数据,是实例的,不是函数的。

在类的实例里
num.eq(othernum); // This is like writing eq(num, othernum)
medium.com/@mattia512maldini/inheritance-is-not-subtyping-b84488eca5ea

最后 在写类的时候记得 组合优于继承,用 IoC,不要在父类子类上耽误时间。use composition (through constructor dependency injection 也就是让 IoC 生成类的实例 ) to put things together and prevent complexity.
codeburst.io/inheritance-is-evil-stop-using-it-6c4f1caf5117
retamia
2020-10-15 16:51:23 +08:00
去看一本叫 SICP 的书就知道了
zjsxwc
2020-10-15 17:06:37 +08:00
没有,“类”就是个语法,
如果你问“对象”有什么作用,那么楼上说的优势都是,
但是有些语言,没有“类”,只有对象,照样还是很火,比如之前版本的 js,
“类”仅仅只是创建“对象”的一种实现途经,但不是唯一。
Hlianbobo
2020-10-15 17:07:40 +08:00
@cmdOptionKana 谢谢回复。你认为 java 哪一本书对面向对象讲的比较透彻。是否有具体推荐?
Hlianbobo
2020-10-15 17:16:24 +08:00
@BoarBoar 你的回复,让我感觉。类,或者说面向对象。其实就是给自己写的函数间隔目录,分个类。这样以后再引用的时候,只要一看到被引用的方法是 A.b.sin 。就知道这个函数是起什么作用的了。因为你看到 A 就想到 A 这一类主要是处理什么工作的。在看到 b 更进一步明确了。类似于中粮集团大豆公司仓库修缮部刘主任。这样一看名字就知道他是做什么工作的了?是这意思么?
那我再命名自己写的函数时按照这一思路去给全局变量函数分类。是不是就实现了面向对象的编程思想?
Hlianbobo
2020-10-15 17:18:58 +08:00
@chaleaoch 我明白全局变量定义的多了。容易出问题。请教一下。类定义以后时如何避免全局变量的风险的?是因为其命名天然就加了一个类名在变量前面么?另外,类是不是天然就可以全局调用?
Wirbelwind
2020-10-15 17:22:31 +08:00
类只是抽象给写程序的人看的,底层里类展开完都是普通类型
Hlianbobo
2020-10-15 17:33:24 +08:00
@retamia 谢谢荐书。看了一下简介。是以 scheme 为例子讲解的。完全没学过这门语言。感觉读起来困难不小吧。另外做数据分析。数据挖掘对编程的技能要达到什么深度?比如面向对象的编程思想在数据挖掘领域应用普遍么?
dreamist
2020-10-15 17:42:18 +08:00
em...要说面向对象的理解,还是学习 Java 好些,python 这样的动态语言,学明白挺不容易的。。
RoyceLee
2020-10-15 17:42:29 +08:00
看看继承和多态就知道类的牛逼
cmdOptionKana
2020-10-15 18:02:58 +08:00
@Hlianbobo 很多 Java 入门书对这个问题都讲得很不错,所以我没记下具体哪本,因为其实讲 Java 就离不开面向对象,Java 就是面向对象思想的极致表现。具体的书可以看看这两本:

https://www.zhihu.com/question/19848946
<p>有一本经典的书《敏捷软件开发, 原则,模式,实践》,里边详细的讲解了一个薪水支付案例,是迄今为止<b>最好的面向对象设计的例子</b></p>

另外有个最经典的 Thinking in Java (Java 编程思想),这本书非常著名,值得一看。
BoarBoar
2020-10-15 18:20:55 +08:00
@Hlianbobo 你这样搞的话就算实现 1/3 的面向对象了,也就是封装。你再想一下,如果以后业务变动,你分好类的变量要加几个进去,但是又不想也不敢动以前的老代码,与其把之前分好类的几百个变量 copy 一遍,继承一下是不是清爽得多?与其把分好类的函数 copy 改改,多态一下是不是整洁得多?
用大白话说,封装就是把变量函数分类,继承多态就是拓展分好类的变量函数。
另外类只是一段格式,在初始化对象时才会分配内存,比起全局变量,毫无疑问资源消耗小得多
wysnylc
2020-10-15 18:44:19 +08:00
你得学个 Java 入门,就知道什么是 OOP 了
Java 被吐槽难学冗余 OOP 有一定功劳
chaleaoch
2020-10-15 19:07:49 +08:00
@Hlianbobo #31
类定义以后时如何避免全局变量的风险的?
类有自己的命名空间, 实例化之后,一个实例就是一个独立的命名空间. 所以将全局变量的空间进行分割啊.

是因为其命名天然就加了一个类名在变量前面么?
即是也不是. 我也说不清楚,参考上一个问题的回答.

类是不是天然就可以全局调用?
不是,参考 java 中的内部类. python 就更简单了, python 可以在类内部定义类,也可以在函数里面定义类.不要太同意.

楼主钻牛角尖了, 我的建议是不求甚解, 快速浏览语法书之后,进项目.慢慢就懂了. 多敲代码.而不是思考.当然思考也不是坏事. 敲代码和思考需要同步进行.加油.
chaleaoch
2020-10-15 19:08:33 +08:00
.不要太同意. --> 不要太简单.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/715238

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX