Difference Between Information Hiding and Encapsulation – 信息隐藏与封装的区别

最后修改: 2023年 10月 15日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Encapsulation is an essential object-oriented programming paradigm. It allows data and methods to be grouped together in a class. However, encapsulation itself doesn’t guarantee defensive programming.

封装是一种重要的面向对象编程范式。它允许在类中将数据和方法组合在一起。但是,封装本身并不能保证编程的防御性。

To achieve robustness, we employ information hiding. Information hiding is a programming principle that promotes the idea of restricting access to internal implementation details.

为了实现稳健性,我们采用了信息隐藏技术。信息隐藏是一种编程原则,它提倡限制对内部执行细节的访问。

In this tutorial, we’ll explore details about encapsulation and information hiding. Additionally, we’ll see some sample code and understand the key differences between the two concepts.

在本教程中,我们将探讨封装和信息隐藏的详细信息。此外,我们还将看到一些示例代码,并了解这两个概念之间的主要区别。

2. Historical Background

2.历史背景

The term “information hiding” was coined by Parnas in 1972 in an attempt to differentiate procedural programming from modular programming.

“信息隐藏 “一词由 Parnas 于 1972 年提出,试图将过程式编程与模块化编程区分开来

Parnas infers that the implementation of data should be unknown to an outside module.

帕纳斯推断,外部模块不应该知道数据的执行情况。

Furthermore, in 1973, Zelis came up with the word encapsulation to explain how to reduce access to underlying data in a class to prevent unwanted modification.

此外,1973 年,Zelis 提出了 “封装”(encapsulation)一词,用来解释如何减少对类中底层数据的访问,以防止不必要的修改。

In 1978, Parnas claimed the words encapsulation and information hiding are synonymous. However, in 2001, Paul Roger showed the difference between encapsulation and information hiding with sample code. He claimed we can have encapsulation without information hiding.

1978年,帕纳斯声称封装和信息隐藏是同义词。然而,2001 年,保罗-罗杰用示例代码说明了封装和信息隐藏之间的区别。他声称,我们可以有封装而没有信息隐藏。

Encapsulation is a broad concept in object-oriented programming that bundles data with methods. This ensures a modular design.

封装是面向对象程序设计中的一个广泛概念,它将数据与方法捆绑在一起。这确保了模块化设计。

Encapsulation and information hiding are sometimes used synonymously, but there are some differences.

封装和信息隐藏有时被当作同义词使用,但两者还是有一些区别的。

3. Encapsulation

3.封装

According to Paul Roger, encapsulation is simply bundling data with operations that act on the data.

保罗-罗杰认为,封装只是将数据与作用于数据的操作捆绑在一起

3.1. Without Encapsulation

3.1.无封装

Let’s see an example class without encapsulation:

让我们来看一个没有封装的示例类:

class Book {
    public String author;
    public int isbn;
}

Here, the Book class has public access modifiers for its fields. This makes the fields accessible from external classes.

在这里,Book 类的字段具有 public 访问修饰符。这使得外部类可以访问这些字段。

Let’s create another class named BookDetails to get the details of a Book object:

让我们创建另一个名为 BookDetails 的类,以获取 Book 对象的详细信息:

class BookDetails {
    public String bookDetails(Book book) {
        return "author name: " + book.author + " ISBN: " + book.isbn;
    }
}

The BookDetails class contains a method that uses Book data. Here, we treat the Book class as a container for data and BookDetails as a collection of methods that act on the data.

BookDetails 类包含一个使用 Book 数据的方法。在这里,我们将 Book 类视为数据的容器,而 BookDetails 类则是作用于数据的方法的集合。

We use a programming procedure that enforces creating an implementation class that operates on data from another class. This programming style is archaic, and it’s not modular.

我们使用的编程程序强制要求创建一个实现类,该类可对来自另一个类的数据进行操作。这种编程方式已经过时,而且不是模块化的。

Here’s a unit test to get the details of a book:

下面是一个获取图书详细信息的单元测试:

@Test
void givenUnencapsulatedClass_whenImplementationClassIsSeparate_thenReturnResult() {
    Book myBook = new Book();
    myBook.author = "J.K Rowlings";
    myBook.isbn = 67890;
    BookDetails details = new BookDetails();
    String result = details.bookDetails(myBook);
    assertEquals("author name: " + myBook.author + " ISBN: " + myBook.isbn, result);
}

The implementation above can be simplified with encapsulation. Changes in Book class affect any classes that use Book data.

上述实现可以通过封装来简化。Book 类中的更改会影响使用 Book 数据的任何类。

3.2. With Encapsulation

3.2.使用封装

Let’s improve the design in the last section using encapsulation. We can bundle the data and the methods operating on it into a single class:

让我们使用封装来改进上一节中的设计。我们可以将数据和对其进行操作的方法捆绑到一个类中:

class BookEncapsulation {
    public String author;
    public int isbn;
    public BookEncapsulation(String author, int isbn) {
        this.author = author;
        this.isbn = isbn;
    }
    public String getBookDetails() {
        return "author name: " + author + " ISBN: " + isbn;
    }
}

Here, we improve the code by bundling the implementation with the class. This makes the code modular. Clients can easily invoke the getBookDetails() methods without having much knowledge of its implementation.

在这里,我们通过将实现与类捆绑在一起来改进代码。这使得代码变得模块化。客户端可以轻松调用 getBookDetails() 方法,而无需了解其实现。

Let’s see a unit test to invoke getBookDetails():

让我们来看看调用 getBookDetails() 的单元测试:

@Test
void givenEncapsulatedClass_whenDataIsNotHidden_thenReturnResult() {
    BookEncapsulation myBook = new BookEncapsulation("J.K Rowlings", 67890);
    String result = myBook.getBookDetails();
    assertEquals("author name: " + myBook.author + " ISBN: " + myBook.isbn, result);
}

Encapsulation improves the code, but external classes can modify the Book data because the fields use a public access modifier. However, encapsulation doesn’t have strict rules on which access modifier to use. We can use the public, private,  and protected access modifiers.

封装改进了代码,但外部类可以修改 Book 数据,因为字段使用了 public 访问修饰符。但是,封装对使用哪种访问修饰符没有严格的规定。我们可以使用 publicprivateprotected 访问修饰符。

Additionally, encapsulation helps introduce a feature to a class without breaking external code using the class. Let’s modify the BookEncapsulation class by introducing an id:

此外,封装有助于在类中引入一项功能,而不会破坏使用该类的外部代码。让我们通过引入 id 来修改 BookEncapsulation 类:

// ...
public int id = 1;
public BookEncapsulation(String author, int isbn) {
    this.author = author;
    this.isbn = isbn;
}
public String getBookDetails() {
    return "author id: " + id + " author name: " + author + " ISBN: " + isbn;
} 
// ...

Here, we introduce the id field and modify the return details of getBookDetails(). These internal changes won’t break any client code. This makes encapsulation powerful and modular.

在这里,我们引入了 id 字段,并修改了 getBookDetails() 的返回详细信息。 这些内部更改不会破坏任何客户端代码。这使得封装功能强大且模块化。

However, we can make encapsulation more strict by applying the idea of “information hiding”. Encapsulation isn’t enough for defensive programming. We need to apply information hiding with encapsulation to prevent unwanted data modification.

不过,我们可以通过应用 “信息隐藏”的思想使封装更加严格。对于防御性编程来说,封装是不够的。我们需要在封装的同时进行信息隐藏,以防止不必要的数据修改。

4. Information Hiding

4.信息隐藏

Information hiding is a programming principle that aims to prevent the direct modification of the data of a class. Also, it provides a strict guideline to access and modify the data of a class.

信息隐藏是一种编程原则,旨在防止直接修改类的数据。此外,它还为访问和修改类的数据提供了严格的指导。

Additionally, it helps to hide design implementations from the client, especially design implementations that are likely to change.

此外,它还有助于向客户隐藏设计实现,尤其是有可能改变的设计实现

Furthermore, information hiding when used with encapsulation ensures modular code.

此外,信息隐藏与封装一起使用时,可确保代码的模块化。

Let’s improve the encapsulated class by applying information hiding:

让我们通过信息隐藏来改进封装类:

class BookInformationHiding {
    private String author;
    private int isbn;
    private int id = 1;
    
    public BookInformationHiding(String author, int isbn) {
        setAuthor(author);
        setIsbn(isbn);
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public int getIsbn() {
        return isbn;
    }
    public void setIsbn(int isbn) {
        this.isbn = isbn;
    }
    public String getBookDetails() {
        return "author id: " + id + " author name: " + author + " ISBN: " + isbn;
    }
}

Here, we use the private access modifier to restrict access and altering of fields from an external class. Furthermore, we create getters and setters to set how the field can be accessed and modified.

在这里,我们使用 private 访问修饰符来限制对来自外部类的字段的访问和修改。此外,我们还创建了 getters 和 setters 来设置如何访问和修改字段。

In contrast to encapsulation without information hiding, where any access modifier can be used, information hiding is implemented through the use of a private access modifier. This restricts access to the fields within the class only.

与可以使用任何访问修饰符的无信息隐藏封装不同,信息隐藏是通过使用 private 访问修饰符来实现的。这就限制了对类内字段的访问。

The fields cannot be directly accessed from a client code, thus making it more robust.

客户端代码无法直接访问这些字段,从而使其更加稳健。

Let’s see a unit test for the modified class:

让我们来看看修改后的类的单元测试:

@Test
void givenEncapsulatedClass_whenDataIsHidden_thenReturnResult() {
    BookInformationHiding myBook = new BookInformationHiding("J.K Rowlings", 67890);
    String result = myBook.getBookDetails();
    assertEquals("author id: " + 1 + " author name: " + myBook.getAuthor() + " ISBN: " + myBook.getIsbn(), result);
}

Additionally, we can create a strict rule on how data can be modified. For instance, we can avoid a negative ISBN by modifying the setter:

此外,我们还可以对如何修改数据制定严格的规则。例如,我们可以通过修改设置器来避免负 ISBN:

public void setIsbn(int isbn) {
    if (isbn < 0) {
        throw new IllegalArgumentException("ISBN can't be negative");
    }
    this.isbn = isbn;
}

Here, we create a strict rule on how to modify the ISBN.

在这里,我们对如何修改 ISBN 制定了严格的规则。

5. Key Differences

5.主要差异

Here’s a summary table showing the key differences between encapsulation and information hiding:

下面的汇总表显示了封装和信息隐藏之间的主要区别:

Information Hiding Encapsulation
A design principle to hide implementation details and unintended modification to data An object-oriented principle that bundles data with functions operating on them.
Strictly uses the private access modifier Not strict on access modifiers and can use a public, private, or protected access modifier
Helps to achieve defensive programming A methodology to achieve information-hiding

6. Conclusion

6.结论

In this article, we learned the key concepts of encapsulation and information hiding. Additionally, we saw an example code that shows the slight differences between encapsulation and information hiding.

在本文中,我们学习了封装和信息隐藏的关键概念。此外,我们还看到了一个示例代码,它显示了封装和信息隐藏之间的细微差别。

However, a school of thought claims information hiding and encapsulation are synonymous. We need to always apply the principles of information hiding when encapsulating a class.

然而,有一种观点认为信息隐藏和封装是同义词。在封装类时,我们需要始终应用信息隐藏原则

As always, the source code for the examples is available over on GitHub.

与往常一样,这些示例的源代码可在 GitHub 上获取。