如果封装不隐藏数据,为什么称为数据隐藏?

Why Encapsulation is called data hiding, if its not hiding the data?

下面两个class在数据隐藏(封装)方面有什么区别

在下面的例子中,我可以通过 public.

来访问 member 的值

例如:1

public class App {
   public int b = 10;

public static void main(String[] args) {
    System.out.println(new App().b);
 }
}

在下面的示例中,我可以使用 getter 方法访问成员的值。

例如:2

class DataHiding 
   {

    private int b;

    public DataHiding() {
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    }

在上面两个例子中,我都可以访问member的值。为什么Eg:2,叫做数据隐藏(封装)?如果它没有隐藏数据。

为什么Eg : 1不叫封装?

如果您想检索 B 的状态而不能更改其值,会发生什么情况?您将创建 getter 而不是 setter,您无法通过将 B 作为 public int.

访问来实现

此外,在 get 和 set 两种方法中,如果我们有一个更复杂的对象,也许我们想要设置或获取一些 属性 或对象的状态。

示例。

private MyObject a;

public setMyObjectName(String name){
     MyObject.name = name;
}

public getMyObjectName(){
     return MyObject.name;
}

通过这种方式,我们通过限制对其状态的访问来保持对象的封装。

使用 mutatorsaccessors 隐藏了逻辑,而不是方法的名称。它防止用户直接修改class成员。

在你的第二个例子中,用户不知道class成员b,而在第一个例子中,用户直接暴露到那个变量,有能力改变它。

想象这样一种情况,您想要在设置 b 的值之前进行一些验证,或者使用您不想公开的辅助变量和方法。您将把逻辑封装在 setter 中,通过这样做,您可以确保用户无法在没有您监督的情况下修改变量。

在java中,所有方法都是虚拟的。这意味着,如果你扩展一些 class,你可以覆盖一个方法的结果。想象下一个 class(继续你的例子):

class DataHidingDouble extends DataHiding{
  public int getB(){
    return b*2;
  }
}

这意味着您在您的子class中保持对 b 对外部世界的控制。 想象一下一些 subclass ,其中 b 的值来自不是变量的东西,例如。一个数据库。如果 b return 是一个变量,你将如何使它成为值。 它隐藏了数据,而不是价值。因为 class 负责维护数据,并且 return 将正确的值传递给外界。

封装不是数据隐藏,它是信息隐藏。您隐藏了内部结构和数据实现以及数据访问逻辑。

例如,如果愿意,您可以在内部将整数存储为 String。在第一种情况下,更改该内部实现意味着您还必须更改所有依赖于 b 成为 int 的代码。在第二种情况下,访问器方法将保护内部结构并为您提供 int,如果内部结构发生变化,您不必更改其余代码。

访问方法还使您有机会限制对数据的访问,使其成为 read-onlywrite-only 除了普通 read-write 访问之外。更不用说可以验证进入对象的数据完整性以及相应地更改对象状态的其他逻辑。

这是关于什么的

当你在这个问题的 and object oriented programming , I suppose you are implicitly thinking about Java Beans. Nevertheless this is a question quite common across languages, take the wikipedia 页面上标记这个问题时:

In programming languages, encapsulation is used to refer to one of two related but distinct notions, and sometimes to the combination1 thereof:

  • A language mechanism for restricting access to some of the object's components.
  • A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.

Some programming language researchers and academics use the first meaning alone or in combination with the second as a distinguishing feature of object-oriented programming, while other programming languages which provide lexical closures view encapsulation as a feature of the language orthogonal to object orientation.

The second definition is motivated by the fact that in many OOP languages hiding of components is not automatic or can be overridden; thus, information hiding is defined as a separate notion by those who prefer the second definition.

所以封装并不是真正关于隐藏数据或信息它关于封装语言组件中的数据片段(Java中的class)。一个JavaBeans封装数据

也就是说,虽然封装是面向对象编程范式的主要特征之一,但在语言设计历史的某个时刻,它被认为不足以帮助设计更好的软件。

历史

实现更好的软件设计的一个关键实践是decoupling, and encapsulation helps on that matter. Yet a cluster of data was not enough to help achieve this goal, other efforts in OOP pioneering were made in different language at that time, I believe SIMULA is the earliest language to introduce some kind of visibility keywords among other concepts like a class. Yet the idea of information hiding really appears later in 1972使用仅与使用它的组件相关的数据以实现更好的解耦。

言归正传。

您问题的答案

  1. 在这种情况下数据被封装并且public

    这通常被称为全局变量,通常被认为是一种糟糕的编程习惯,因为这可能会导致耦合和其他类型的错误

  2. 数据被封装并且public(通过方法访问器)

    这个 class 通常被称为 Java Bean,如果用在它们设计目的之外的任何地方,这些都是令人厌恶的。

    这些对象被设计来完成一个单一的角色,这是非常具体的是根据 specification

    2.1 What is a Bean? Let's start with an initial definition and then refine it:

    “A Java Bean is a reusable software component that can be manipulated visually in a builder tool.”

    为什么现在它很可恶?因为人们,框架供应商通常会滥用它们。规范对此还不够清楚,但是有一些关于这方面的声明:

    So for example it makes sense to provide the JDBC database access API as a class library rather than as a bean, because JDBC is essentially a programmatic API and not something that can be directly presented for visual manipulation.

    我宁愿引用 Joshua Bloch(更多内容在 ):

    "The JavaBeans pattern has serious disadvantages." - Joshua Bloch, Effective Java

相关点数

如上所述,实现更好软件的一个关键实践是解耦。耦合一直是软件工程师最古老的战场之一。封装、信息隐藏与以下有助于解耦的实践有很大关系,原因有很多:

  • the Law of Demeter, breaking this law means the code has coupling. If one has to traverse a whole data graph by hand then, there's no information hiding, knowledge of the graph is outside of the component, which means the software is therefore less maintainable, less adaptable. In short : refactoring is a painful process. Anemic domain model 受此困扰,它们被认为是反模式。

    一种不违反得墨忒耳法则的现代实践是Tell, Don't Ask

    That is, you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do.

  • immutability,如果数据必须是 public,它应该是不可变的。在某种程度上,如果不需要数据,一个模块可以在另一个模块中引入副作用;如果单线程程序是这样,那么多线程软件就更痛苦了。现在的软件和硬件越来越多线程,线程要通信,如果一个信息要public就应该是不可变的。不变性保证了线程安全,少了一件需要担心的事情。还必须保证整个对象图的不变性。

    class IsItImmutable {
      // skipping method accessors for brevity
    
      // OK  <= String is immutable
      private final String str;
    
      // NOK <= java.util.Date is mutable, even if reference is final a date can be modified
      private final Date  date;
    
      // NOK <= Set operations are still possible, so this set is mutable
      private final Set<String> strs;
    
      // NOK <= Set is immutable, set operations are not permitted, however Dates in the set are mutable
      private final Set<Date> udates = Collections.unmodifiableSet(...);
    
      // OK  <= Set is immutable, set operations are not permitted, String is immutable
      private final Set<String> ustrs = Collections.unmodifiableSet(...);
    }