【问题标题】:What is encapsulation? How does it actually hide data?什么是封装?它实际上是如何隐藏数据的?
【发布时间】:2011-08-06 03:22:16
【问题描述】:

搜索出现了一个简单的定义:数据隐藏。

但是,请考虑以下两个示例:

1) 第一个例子:

Class Employee
{
    public int age;
}

2) 第二个例子:

Class Employee
{
    private int age;

    public int getAge(){return age;}
}

问题:
在上面指定的两个示例中,没有数据隐藏,因为age 要么被其他人修改,要么被其他人查看。数据隐藏在哪里?封装对上述示例有何帮助?

【问题讨论】:

  • 你读过维基百科的文章吗:en.wikipedia.org/wiki/…
  • @Reno,封装不仅仅意味着保护数据不被修改。如果我再添加一个 setter 方法怎么办……根据您的解释,这意味着封装意味着类的只读属性……这不是……我确定……
  • 另见:Why Properties Matter by Jon Skeet

标签: .net oop design-patterns encapsulation hidden-field


【解决方案1】:

数据隐藏。第二个示例隐藏了值的存储方式。此外,第二个示例使该值对于类外的代码是只读的。通过拥有私有字段并通过方法或属性公开它们,您会立即获得一些优势,其中一些是:

  • 访问控制粒度;您可以选择将值公开设为只读、读写或只写。
  • 可以在存储值之前验证输入
  • 可以添加日志记录或其他审计机制

请注意,封装不仅仅涉及访问控制。封装的主要用途是对调用代码隐藏实现细节。当调用代码想要检索一个值时,它不应该依赖于从哪里来这个值来自哪里。在内部,该类可以将值存储在字段中或从某些外部资源(例如文件或数据库)中检索它。 也许该值根本不存储,而是即时计算的。这与调用代码无关。

当您通过方法或属性公开值时,您将调用代码与此类细节屏蔽开来,这也为您提供了更改实现的可能性,而不会影响调用代码。

【讨论】:

  • 那么是不是意味着给属性添加setter方法会破坏封装呢?
  • @anil:不,一点也不。封装是关于隐藏实现细节。通过使字段私有并通过方法公开它,您可以封装内部实现细节。该值可以存储在字段中,磁盘上的文件中,数据库中,可以即时计算,等等。调用代码确实(并且应该)不知道这些细节。那就是封装。
  • 我猜隐藏实现细节与抽象而不是封装有关。现在听起来两个不同的名称被用于同一个术语。看看这个链接:en.wikipedia.org/wiki/Abstraction_%28computer_science%29
  • @anil:我会说封装是一种抽象形式。您链接到的文本也支持这一点:术语封装是指隐藏状态细节(在Abstraction in object oriented programming段落中)
【解决方案2】:

在您的第一个示例中,变量年龄设置为公共变量。在这里,当声明 Employee 类型的对象时,任何人都可以修改 meeber 年龄。

但是,在您的第二个示例中,变量 age 实际上是私有的,并且只能从 Employee 类内部进行修改。这就是数据隐藏的情况。

在面向对象的编程中,封装是指一个对象由另一个对象组成。这与继承相反,在继承中,对象可以扩展已经存在的类。

【讨论】:

  • 正如我在其他人的回复中已经评论过的那样,你的意思是只有一个 setter 会破坏封装。你的意思是只读属性可以实现封装。我确定不是。由于每个人都基于第二种方法进行响应,但是如果添加一个简单的 setter 方法呢?
【解决方案3】:

封装将某物做什么的概念与它的实现方式分开。

封装是面向对象编程中一个非常重要的概念。它隐藏了应用程序中其他模块的数据。在您的示例 2 中,如您所见,您只能使用 getter 方法获取年龄和年龄,但您只能将值设置为该类内的私有成员,而不能设置在该类之外。这就是封装的优势。

【讨论】:

  • 多态性是如何加入这个队伍的?
  • @GregC,哎呀!我的意思是封装。感谢您指出。 :)
【解决方案4】:

想想这个变种:

class Employee
{
    private int _age;

    public string Age
    {
        get { return _age.ToString(); }
    }
}

在您的示例中,外部和内部使用整数,这令人困惑。 (类似于显示 2 * 2 = 4 来解释乘法并忘记了 2 + 2 = 4)

【讨论】:

  • @UGEEN,Erno,在内部和外部使用相同的数据类型不会造成任何混淆。听起来很奇怪,您出于多种原因将其转换为字符串,客户端可能需要将其作为整数。那么是否有任何真正的理由将其转换为字符串......此外它如何帮助封装?
  • 转换为字符串只是为了表明外部类型与内部可能有很大不同。当然,当客户需要它作为整数时,Age 属性应该是那种类型。例子只是为了说明property-get封装(或者可以封装)内部数据格式。
【解决方案5】:

封装不仅仅是数据隐藏。封装允许您保留与该实体相关的所有数据和功能。此数据的可见性级别是一个相关但不完全相同的概念。例如。 Employee 对象包含所有员工数据和功能(方法)。请注意,这不是强制,而是由 OO 语言启用

如果您出生在 OO 时代,这对您来说可能听起来很自然,但这是从函数式编程到 OOP 的重大飞跃,无论是概念(设计)还是支持这种范式的语言。

引自维基百科article

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

  • 一种语言机制,用于限制对某些 对象的组成部分。
  • 一种便于将数据与 方法(或其他功能) 对这些数据进行操作。

【讨论】:

    【解决方案6】:

    假设我像这样使用你的代码:

    Employee employee = new Employee();
    int age = employee.getAge();
    // Do something with age
    

    在这里,除非我查看您的源代码,否则我完全不知道Employee 是如何计算其年龄的。据我所知,getAge() 可能如下所示:

    public int getAge() {
        return new java.util.Random().nextInt( 100 );
    }
    

    或者更复杂的东西。我只是不知道。

    所以在你的第二个例子中,getAge() 只返回一个私有成员变量的事实对我完全隐藏。

    【讨论】:

      【解决方案7】:

      Encapsulation 就是data hiding

      让我们看看封装是如何发生的。 假设您创建了一个 Employee 类并包含两个实例变量。姓名和工资。您不会将它们设为私有。现在程序中的另一个类可以通过创建一个对象来访问这两个变量,如果雇员类。所以我们想要的是将这两者或薪水信息隐藏到外部班级。

      如果我们想隐藏薪水 我们可以简单地将薪水声明为private 变量。现在我们知道,甚至另一个类也创建了一个对象并尝试访问薪水,因为它不起作用。因为它是一个私有字段,只有 Employee 类可以访问。现在我们已经隐藏了我们的数据。

      但是假设我们需要一个人来输入每个员工的工资细节。 我会说得更清楚。 数据录入者有3类数据要录入woked_hours, OT and leaves(Emplyee类为此设置了三个变量)。 我们希望此人输入这些详细信息,但我们将do not want 他到see salary calculation 是如何完成的。它是根据 Employee 类内部的数学方程完成的。

      所以他不能自己计算和输入薪水。但是我们让他看看最终的薪水。在那里我们创建了一个方法来获取员工类中的薪水值。这是

      public int getSalary()
      {
         return salary;
      } 
      

      他知道这一点,他可以使用两种方法来访问那些隐藏字段。 set method and get method. 所以他call getmethod. 是他can see salary 信息。因为我们创建了 getMethod 来返回薪水。现在他尝试使用set方法输入一个新的工资金额来改变工资的当前值。所以他打电话给e.setSalary(1000); 但它给出了一个错误。为什么?因为在员工类中没有写成

      的方法
         public void setSalary(int newSalary)
         {
         salary=newSalary;
         }
      

      我们故意不编写该代码,因为我们不希望他立即设置工资值。所以我们隐藏了一些信息,但我们仍然让他访问一些信息。我们允许他访问Read only。但是not Write 是工资。

      既然我们已经完成了封装,它不是很有用吗?

      就像他被允许set这些字段woked_hours, OT and leaves一样。对于那些字段,我们已授予他只写权限。我们故意不写​​getter methods。如果你同时写了getter 和setter,你就允许他READ/ Write 两者都可以访问。

      只设置或获取都没有关系,该字段是私有的,该字段已隐藏,数据已隐藏。但是通过getterssetters 提供了一些访问权限。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-13
        • 1970-01-01
        • 2013-11-25
        • 2017-03-20
        • 1970-01-01
        • 2011-09-04
        • 1970-01-01
        相关资源
        最近更新 更多