在编程中,“你希望发生什么”(一种抽象设计)和“你如何让它发生”(实现某种结果的规则的具体表达)之间存在着持续的紧张关系。如果我们有一台计算机甲骨文(不要与甲骨文公司混淆),我们可能会问“生命的意义是什么?” 并得到答案(当然是 42)。但我们不这样做:我们必须告诉计算机以繁琐的小步骤来做事。
一旦你将一个问题分解为一个可执行的算法,使用组件,你就会开始遇到这些组件如何交互的问题。程序员弄错了,导致片段交互不正确。需求变化:一个由许多执行 A 的部分组成的程序,现在必须执行 B 代替(或附加)。出于成本和时间的原因,我们希望重新利用旧代码来做新的事情。所有这些都会导致错误。要是我们能有可理解的、行为良好的大步骤,我们只是由可理解的、行为良好的小步骤组成……
许多早期的语言都是“面向动词的”:创建一个简单的机器级变量(如INTEGER
or REAL
)、修改它、ADD X AND Y GIVING Z
等等。如果您需要构建大量状态来描述某物(例如火星着陆器),那么您有大量变量来保存所有部分。然后将错误的动词应用于错误的部分变得太容易了,例如尝试读取降落伞的温度,或者使用仅在轮子上起作用的功能旋转轨道推进器。
“类型化”语言提供了一种抑制不良交互的方法。如果rotate
函数/过程只对一个wheel
类型进行操作,你就不会在 RCS 系统上意外调用它。但是最终你会得到大量的动作动词,thruster_rotate
并且wheel_rotate
(尽管一些类型语言提供了命名空间,以便你可以做thruster.rotate(thruster_id)
或类似的事情,这不会干扰wheel.rotate(wheel_number)
)。
面向对象编程提供了一种不同的方法:程序的状态可以根据单独的“对象状态”来保存,访问器对这些对象进行操作。现在thruster.rotate()
可以wheel.rotate()
在使用轮子的同时使用 RCS 推进器。它是,或者至少可以是,更清楚什么在做什么。(请注意,OOPL 也可以而且通常确实也有花哨的命名空间。)
唉,人还是会犯错。访问器为您(作为程序员)提供了一种方法,允许系统的其他部分(通常由其他人编写)以良好控制的方式与“您的对象”交互,并且可能对他们更有用。如果您有温度传感器,您可以提供两者的读数,degrees_F
即使degrees_C
在内部,实际读数也以微伏为单位。保护(无论执行得多么松散——有人指出,C++ 必须来自自由恋爱时代,因为它让朋友可以访问你的私人部分)至少允许你以代码形式陈述你的意图,即谁应该摆弄什么.
最后,编程通常与抽象有关:暴露需要暴露的东西,但同时隐藏不应该暴露的东西。访问器和保护使您可以直接控制公开的内容和隐藏的内容。即使它们主要是建议性的(如在 Python 中),它们仍然是一个直接的声明:“如果你不处理这个模块,你不应该使用或修改这个东西。这只是一个实现细节,而不是一部分的界面。”