Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在OOP中,类封装是进行数据隐藏的正确方法吗?_Oop_Encapsulation_Data Hiding - Fatal编程技术网

在OOP中,类封装是进行数据隐藏的正确方法吗?

在OOP中,类封装是进行数据隐藏的正确方法吗?,oop,encapsulation,data-hiding,Oop,Encapsulation,Data Hiding,我对数据隐藏的OOP原理有一个疑问 据我了解,, 数据隐藏=将结构的内部字段限制在某个可视区域。 动机:如果一个人改变了结构内容,那么只有可视性领域的实现需要改变 为了实施数据隐藏原则,oop设计师大多决定这样做: 方法1: 封装=使结构本身(类)成为可视区域,将对其进行操作的函数(方法)放在内部 这对我来说似乎是一个很大的要求。造成了很多不必要的不对称。 为什么OOP设计人员没有决定以这种方式定义封装: 方法2: 让程序员控制可视区域应该是什么。一个可视区域可能包括多个结构,而不仅仅是一个。

我对数据隐藏的OOP原理有一个疑问

据我了解,, 数据隐藏=将结构的内部字段限制在某个可视区域。 动机:如果一个人改变了结构内容,那么只有可视性领域的实现需要改变

为了实施数据隐藏原则,oop设计师大多决定这样做:

方法1:

封装=使结构本身(类)成为可视区域,将对其进行操作的函数(方法)放在内部

这对我来说似乎是一个很大的要求。造成了很多不必要的不对称。 为什么OOP设计人员没有决定以这种方式定义封装:

方法2:

让程序员控制可视区域应该是什么。一个可视区域可能包括多个结构,而不仅仅是一个。 在此可视区域中定义可在多个结构之间操作的函数。 通过这种方式,结构和函数更加独立,更加对称,可能需要更少的getter/setter

让我给你举个例子:如果你有一个玻璃物体和一个瓶子物体,里面有一些水。假设您希望实现从瓶子中填充玻璃的功能

在方法1中,您被迫做一些不对称的事情,您必须要么实现glass.fill(瓶子),要么实现瓶子.fill(玻璃),所以听起来您有一个不必要的难题需要解决。不仅如此,假设您实现了glass.fill(瓶子),现在您在glass的范围内,您无法访问瓶子的内部,所以您必须在瓶子中编写一个方法,以便能够更新它。 对我来说,这听起来像是很多不必要的工作,而这个强制瓶更新方法听起来对数据隐藏更有害

使用方法2,您可以定义一个独立的填充物(玻璃、瓶子),它可能只知道玻璃和瓶子的内部结构,因为玻璃、瓶子和填充物可能是同一可视区域的一部分。听起来不是容易多了吗? 注意,您仍然可以使用这种方法定义协议(接口), 从外部看,你需要知道的是,玻璃和瓶子是未指定的东西,填充是一个操作,操作两件事:一个玻璃和一个瓶子


我的论点有缺陷吗?编程语言有没有强调这种分类方法的尝试?

在编程语言设计(IMHO)的“哲学”层面上,真的没有对错之分。大多数编程语言确实提供了某种程度的“包”可见性,允许定义在一起的类以更开放的方式相互访问

从数据隐藏的角度来看,
fill(瓶子,玻璃)
是否比
瓶子::fill(玻璃)
有任何优势,这个问题对我来说是不透明的,但我认为复杂性可以通过两种方式隐藏。不过我学到的是,拥有有方向的依赖关系图总比拥有循环或双向依赖关系要好。

你说“方法2”可能需要“更少的getter/setter”。这很奇怪,因为“方法1”应该已经不需要了。如果行为在数据所在的位置,则不需要“获取”或“设置”内容

第二,“方法2”是否“更容易”,或者“方法1”是否“强迫”你以违反直觉的方式做事,因为你根本不重要。真正重要的是,从长远来看,代码是否可维护。写起来难不难,写起来不方便都无关紧要,因为更重要的是读者理解它,而变化大多是本地化的


这就像马克·吐温的名言:“我没有时间写一封短信,所以我写了一封长信。”。编写简单易懂的代码很难。约束,即强迫作者使用某些习语或风格是好的(好吧,假设约束是有意义的)

以玻璃和瓶子为例,您希望玻璃响应的信息是“接收此体积的水”;瓶子响应的信息是“供应这一体积的水”

玻璃杯不需要知道水从哪里来,瓶子也不需要知道水往哪里去。所有的玻璃物体需要知道的是要填满它的容量或供水量;瓶子知道供水,直到它是空的或收到停止的信息

因此,玻璃响应“填充”消息的方法签名将是
void glass::fill(双容量)
,瓶子响应“supply”消息的方法签名将是
double瓶::pour()
。(可以想象,“浇注”和“填充”将以增量进行。)

正如您所看到的,使用这种方法,您不需要共享任何内部知识。例如,
glass::fill()
方法将一直工作,直到达到一个内部不变量,例如它的容量,这时它可以抛出一个异常“glass full”;类似地,
瓶子::倾倒()
方法将一直工作,直到瓶子变空,或者捕捉到“玻璃已满”异常,此时倾倒将停止

--


我发现许多开发人员错误地认为对象需要始终直接通信。但事实并非如此;通常,他们会收到“外部世界”的快照,作为他们处理的消息的一部分。在上面的例子中,发送到
玻璃
对象的快照是在特定时刻倒出的水的体积(这就是为什么我推断在数字世界中倒出和填充将以增量方式进行)。

通常,瓶子既不能自动填充玻璃,也不能单独填充玻璃,把瓶子装满。有一个外部协调器w