什么是封装?

时间:2015-02-19 17:05:00

标签: java oop encapsulation

我有两个封装定义,不能适合一个定义。

  1. 封装是数据隐藏。使用私有受保护公开,将数据打包成单个组件。
  2. 无论是什么变化都封装它。保护任何易于改变的东西。
  3. 这两个定义如何讨论相同的概念?

5 个答案:

答案 0 :(得分:14)

封装可能是最容易被误解的OOP概念。

封装不是数据隐藏!

“封装”来自“胶囊”。这意味着将事物放在一起,将它们关在一个包中,我们在这里讨论的“事物”是数据和功能。没有封装的编程意味着处理数据的函数在代码中的某处“浮动”,虽然它们处理数据甚至将特定类型作为输入,但它们与数据分离。

让我举一个例子而不关注“公共”等等:如果你有一个处理复数的类,它有一个真实和想象的部分,你可以简单地定义它:

class complex {
    double real;
    double imaginary;
};

使用旧的预封装样式(例如在C中使用)来获取此数字的绝对值,您将定义如下函数:

double absolute(double real, double imaginary);

这根本不会与班级有关!当然,您也可以定义一个将类复杂作为输入的函数,但它仍然是一个外部函数。因此,要使用它,您必须这样做:

complex A;
A.real = 1;
A.imaginary = -3;

并获得您必须致电的绝对值

absolute(A.real, A.imaginary);

相反,您可以使用封装和将数据和功能放在一起

class complex {
    double real;
    double imaginary;
    double absolute();  // inside the class, encapsulated into it!
};

然后要获得绝对值,您只需调用类似

的方法
A.absolute();

这根本不需要数据隐藏。优点是代码更易于管理,因为您可以清楚地看到所有相关的“事物”(即数据和功能)组合在一起,因此您可以一眼就知道您拥有的内容(数据)以及您可以使用的内容它(方法)。

如果没有这个,就不可能隐藏信息,因为这意味着你从外部限制对某些成员(私有成员)的访问,因此你必须在里面有一些方法,否则你将无法做任何事情。你的数据!

同时,信息隐藏有助于充分利用封装:如果人们可以从外部访问数据,那么让其他编写器编写自己的(未封装的)代码来处理您的数据将会非常危险数据,如果实现不完全兼容,至少会导致代码重复(即无用的努力)和不一致。相反,数据隐藏意味着每个人都必须使用所提供的公共方法访问私有数据,这样每个人都可以使用它们。

因此,数据隐藏需要封装才有意义,同时数据隐藏也有助于实现封装。他们一起工作得很好,但他们不是一回事!

回到你的问题:鉴于此,定义1是错误的。而且,正如CommuSoft所指出的那样,并不是一个真正的定义,这是一个经验法则。我将补充一点,关于何时使用数据隐藏而不是封装是一个经验法则。

另一方面,电子表示这可能与this question重复。我认为值得注意的是,大多数答案都是错误的,包括最佳答案,它提供了封装的一个例子,实际上与封装相反。

如果您想要外部参考,请参阅以下两篇文章:

Encapsulation is not information hiding

Abstraction, Encapsulation, and Information Hiding(请注意,当他开始一个名为“ENCAPSULATION”的段落并引用了很多定义时,他只是试图表明围绕这个主题的混淆;这些定义是错误的,正如他稍后解释的那样!)

答案 1 :(得分:6)

隐藏数据与控制有关。当您隐藏数据时,将其隐藏在其他程序员(您将来自己包含在内)中,因为他们可能会对数据执行不正确的操作,因为他们并不像您那样了解它。因此,您需要仔细控制他们如何使用数据 - 在这种情况下,通过隐藏它来限制访问和可见性。

封装并不是“保护易于改变的一切”的做法。 claim this过度概括的文章,因为大多数软件开发技术都是关于“保护”我们以后可能会改变的事情。你应该知道的是,检查容易发生变化的事情通常是一个好主意,并决定你想要对其他人如何看待和使用这些东西的那种约束 - 你如何封装这些东西。


......同样,封装也不是“将功能与数据放在一起”的做法,正如在另一个答案声明中链接的一些文章。适当的术语可能是模块化,或者简单的旧的面向对象的编程 - 有许多相关的概念。这些技术可以带来封装,但称其封装是令人困惑的,特别是对于初学者。封装真的是“隐藏”数据。 (举一个稍微高级的例子,在JavaScript中,你可以将一个值与一个函数一起作为函数对象的一个​​属性,或者通过一个闭包。这些都不使用字段,它们不涉及使用类的方法/ object / prototype,都将数据和函数“放在一起”,但只有闭包才会通过强制访问约束来封装数据。)

答案 2 :(得分:1)

封装实际上是数据隐藏。原因是将类似的功能组合在一起,以后可以更易于管理的方式进行更改。

封装可能不仅仅是通过使用可见性修饰符来实现。

答案 3 :(得分:1)

我会选择第二个作为封装的定义。我以同样的方式看待它。封装是一种保护代码不受更改影响的机制。

第一个陈述更具限制性。使用封装,您不仅可以隐藏数据,还可以隐藏实现。可见性修饰符只是获得封装的手段。您可以将 public 用于从其他类访问的方法。更改这些会影响调用它们的外部代码。虽然 private 隐藏了您不希望外部可见的内容,并且可以自由地进行分组而不会影响其他类。

所以第二个语句是封装的定义,而第一个是关于如何获取封装的提示。

答案 4 :(得分:0)

引用维基百科:

“封装是将数据和功能打包到单个组件中。封装的功能在大多数面向对象的编程语言中都使用类来支持,尽管还存在其他替代方案。

在编程语言中,封装用于指代两个相关但不同的概念中的一个,有时用于它们的组合:

  1. 用于限制对某些对象组件的访问的语言机制。

  2. 一种语言结构,有助于将数据与对该数据进行操作的方法(或其他功能)捆绑在一起。“