抽象和封装之间的区别是什么?

时间:2014-07-30 05:34:35

标签: oop encapsulation abstraction

在采访中,我被要求解释抽象和封装之间的区别。

是我的回答
  • 抽象让我们能够以最简单的方式表现复杂的现实世界。它是识别对象应具备的相关品质和行为的过程;换句话说,代表必要的特征而不代表背景细节。

  • 封装是一个隐藏对象的所有内部细节与外部现实世界的过程。单词" encapsulation",就像"封闭"进入"胶囊"。它限制客户端看到实现抽象行为的内部视图。

我认为通过上面的回答,面试官确信,但后来我被问到,如果两者的目的都隐藏了,那么为什么需要使用封装。那时候我没有很好的答案。

我应该添加什么来使我的答案更完整?

24 个答案:

答案 0 :(得分:62)

抽象与将接口与实现分离有关。 (我们不关心它是什么,我们关心它以某种方式运作。

封装与禁止访问或了解实现的内部结构有关。 (我们不关心或者不需要看它是如何工作的,只是它确实如此。)

有些人确实使用封装作为抽象的同义词,这是(IMO)不正确的。你的面试官可能会这么想。如果是这种情况,那么当你提到“封装”时,你们每个人都在谈论两件不同的事情。


值得注意的是,这些概念在不同的编程语言中表现得不同。几个例子:

  • 在Java和C#中,接口(在某种程度上,抽象类)提供抽象,而访问修饰符提供封装。
  • 除了我们没有接口,我们只有抽象类之外,它在C ++中的处理大致相同。
  • 在JavaScript中,duck typing提供抽象,而closure提供封装。 (命名约定也可以提供封装,但只有当所有各方同意遵循它时才有效。)

答案 1 :(得分:51)

简单!

以电视为例 - 它是封装,因为:

  1. 电视装有不同的功能,我不知道,因为它们是完全隐藏的。

  2. 像音乐,视频等隐藏的东西捆绑在一个我们称之为电视的胶囊中

  3. 现在,抽象是当我们对某事有所了解时,它可以帮助我们操纵一些我们不知道它如何在内部工作的东西。

    例如: 电视的遥控器是抽象的,因为

    1. 使用遥控器我们知道按数字键会改变频道。我们不知道内部究竟发生了什么。我们可以操纵隐藏的东西,但我们不知道如何在内部完成。
    2. 以编程方式,当我们能够以某种方式访问​​隐藏数据并知道某些东西时......就是抽象......当我们对内部的封装一无所知时。

      没有遥控器,我们无法在电视上改变任何内容,我们必须看到它显示的内容,因为所有控件都被隐藏了。

答案 2 :(得分:15)

抽象

公开实体而不是实体的细节。

“有详细信息,但我们不考虑它们。它们不是必需的。”

示例1:

各种计算: 加法,乘法,减法,除法,广义,罪,余,谭。

我们没有显示我们如何计算Sin,Cos或Tan的细节。我们只是显示计算器,它的各种方法将是,并且需要由用户使用。

示例2:

员工有: 名字,姓氏,中间名。他可以登录(),退出(),DoWork()。

Logging employee In可能会发生许多进程,例如连接数据库,发送员工ID和密码,接收来自数据库的回复。虽然存在上述细节,但我们将隐藏细节并仅公开“员工”。

封装

正在封闭。将多个特征/功能视为一个单元而不是个体。 所以外面的世界会直接引用那个单位而不是它的细节。

“有详细信息,我们会考虑它们,但不要显示它们,而是展示您需要查看的内容。”

示例1:

而不是将其称为加法,减法,乘法,除法,现在我们将其称为计算器。

示例2:

现在所有特征和操作都由员工推荐,例如“John”。约翰有名字。 John Can DoWork()。约翰可以登录()。

隐藏

隐藏来自外部世界的实施。 所以外面的世界不会看到不应该看到的东西。

“有详细信息,我们会考虑它们,但我们不会显示它们。您不需要看到它们。”

示例1:

您的要求:加法,减法,乘法,除法。您将能够看到它并获得结果。

您无需知道操作数的存储位置。这不是你的要求。

此外,我正在执行的每条指令也不是您的要求。

示例2:

约翰想知道他的出勤率。所以GetAttendancePercentage()将被调用。

但是,此方法需要保存在数据库中的数据。因此它将调用FetchDataFromDB()。 FetchDataFromDB()不需要对外界可见。

因此我们将隐藏它。但是,John.GetAttendancePercentage()将对外界可见。

抽象,封装和隐藏相互补充。

因为我们在细节上创建抽象级别,所以细节被封装起来。因为它们是封闭的,所以它们是隐藏的。

答案 3 :(得分:11)

抽象和封装之间的区别: -

<强>抽象

  1. 抽象解决了设计层面的问题。
  2. 抽象用于隐藏不需要的数据并提供相关数据。
  3. 抽象让您可以专注于对象的作用而不是对象的作用。
  4. 抽象 - 外部布局,用于设计。 例如: - 移动电话的外观,就像它有一个显示屏和键盘按钮来拨号。
  5. <强>封装

    1. 封装解决了实现级别的问题。
    2. 封装意味着将代码和数据隐藏到一个单元中,以保护数据免受外界影响。
    3. 封装意味着隐藏对象如何做某事的内部细节或机制。
    4. 封装 - 内部布局,用于实现。 例如: - 移动电话的内部实施细节,键盘按钮和显示屏幕如何使用电路相互连接。

答案 4 :(得分:5)

<强>封装

从你学到的谷歌搜索封装,是一个概念,将相关的数据和操作组合在一个胶囊中或我们可以说是OOP中的一个类,这样任何其他程序都无法修改它所拥有的数据或方法实现它具有特定的时间。只有getter和setter方法才能提供对实例变量的访问。

我们的代码可能会被其他人使用,未来的升级或错误修复也会受到责任。封装是确保我们在代码中执行的任何代码更改都不会破坏使用它的其他代码的原因。

封装增加了代码的可维护性,灵活性和可扩展性。

封装有助于隐藏接口背后的实现。

<强>抽象

抽象是实际隐藏接口背后的实现的过程。所以我们只是意识到实际的行为,而不是内部思维的确切运作方式。最常见的示例可能是将密钥放入锁中并轻松解锁的情况。所以这里的界面是钥匙孔,而我们并不知道锁内的杠杆如何协调它们以锁定锁。

更清楚的是,抽象可以解释为对不同对象使用相同接口的能力。可以存在相同接口的不同实现,而每个实现的细节都通过封装隐藏。

最后,直到现在才回答所有混淆的声明 - 隐藏的部分与封装有关,而暴露的部分与抽象有关。

Read more on this here

答案 5 :(得分:3)

封装:假设我有一些机密文件,现在我将这些文件隐藏在一个储物柜内,这样就没有人可以访问它们了,这就是封装。

抽象:发生了一件大事,报纸上对此进行了总结。现在报纸上只列出了实际事件中更重要的细节,这就是抽象。此外,事件的标题突出显示了一行中更具体的细节,从而为事件提供了更高级别的抽象。足球/板球比赛的亮点也可以被视为整场比赛的抽象。

因此,封装隐藏了数据以保护其完整性,而抽象则突出了更重要的细节。

在编程方面,我们可以看到一个变量可以被包含在一个类的范围内作为私有,从而防止它被直接从外部访问,这是封装 。而一个函数可以写在一个类中以交换两个数字。现在可以通过使用临时变量或通过位操作或使用算术运算来交换数字,但是用户的目标是接收交换的数字而不管用于交换的方法,这是抽象< /强>

答案 6 :(得分:3)

抽象:抽象是收集或收集相关数据并删除不相关数据的过程。 (如果你已经实现了抽象,那么封装也会实现。)

封装:封装是一个将函数和成员包装在一个单元中的过程。意味着您正在隐藏实现细节。意味着用户可以通过制作课堂对象来访问,他/她无法看到细节。

示例:

 public class Test
   {
    int t;
    string  s;
 public void show()
  {
   s = "Testing";
   Console.WriteLine(s);
   Console.WriteLine(See()); // No error
  }

 int See()
  {
   t = 10;
   return t;
  }

 public static void Main()
  {
  Test obj =  new Test();
  obj.Show(); // there is no error
  obj.See(); // Error:- Inaccessible due to its protection level
  }
 }

在上面的例子中,User只能使用obj访问Show()方法,即Abstraction。

See()方法在封装的Show()方法内部调用,因为用户不知道Show()方法中发生了什么。

答案 7 :(得分:3)

我知道在我面前有很多答案,各种各样的例子 那么这就是我的观点抽象正在从现实中获得兴趣

抽象中,我们隐藏了某些内容以降低其复杂性封装中,我们隐藏了一些内容以保护数据。

因此,我们将封装定义为在单个实体中称为类的数据和方法的包装。

在java中,我们使用getter和setter实现封装,而不仅仅是通过将数据和方法包装在其中。我们还定义了一种访问该数据的方法。 在访问数据时我们也会保护它。

技术,例如,将定义私人数据变量呼叫权重。现在我们知道在现实世界的场景中权重不能为零或小于零。
想象一下,如果有没有吸气剂和安装者可以轻易地将其设置为负值,成为班级的公共成员。

现在使用一个真实世界的例子,最后的差异,
考虑一个由开关和按钮组成的电路板。 我们将所有电线包裹在一个电路盒中,以便我们可以通过不直接接触来保护某人(封装)。

我们不关心这些电线是如何相互连接的,我们只想要一个接口来打开和关闭开关。该界面由按钮(抽象

提供

答案 8 :(得分:2)

抽象:在硬件抽象层的情况下,你有简单的接口来触发硬件(例如,左/右转动),而不知道背后的硬件细节。所以隐藏了系统的复杂性。这是现实世界的简化视图。

封装:隐藏对象内部。对象是现实世界的抽象。但是这个对象的细节(比如数据结构......)可以通过封装来隐藏。

答案 9 :(得分:2)

抽象数据封装的众多优势之一。我们也可以说数据封装是实现抽象的一种方式。

答案 10 :(得分:2)

摘要:“提取基本信息的问题的视图     与特定目的相关并忽略其余部分     信息。“[IEEE,1983]

封装:“封装或等效信息隐藏是指     在对象中包含它需要的一切的实践,以及     此外,以这样的方式做到这一点,没有其他对象需要     要注意这个内部结构。“

答案 11 :(得分:2)

抽象是指在不包含背景细节或解释的情况下表示基本要素的行为。

封装是一种用于隐藏对象的属性和行为并仅在适当时允许外部访问的技术。它可以防止其他对象直接更改或访问封装对象的属性或方法。

抽象和封装之间的区别

1.Abstraction专注于对象的外部视图(即接口)Encapsulation(信息隐藏)阻止客户端在视图内部看到抽象行为。

2.Abstraction解决了设计方面的问题,而封装是实现。

3.Encapsulation是抽象的可交付成果。封装几乎没有谈到将抽象分组以满足开发人员的需求。

答案 12 :(得分:1)

在我看来,封装是程序员通过使用访问说明符来隐藏程序代码的复杂性的想法 抽象是根据功能和行为分离方法和对象的地方。例如,汽车有车床,车轮,休息,前大灯。

答案 13 :(得分:1)

开发人员A,其本质上使用抽象的概念将使用模块/库函数/小部件,仅关注它所做的 (以及什么它将用于)但不是如何它。该模块/库函数/小部件的界面(&#39;杠杆&#39;开发者A被允许拉/推)是该抽象的拟人化。

正在寻求创建这样的模块/功能/小部件的开发人员B将利用封装的概念来确保开发人员A(以及使用该小部件的任何其他开发人员)可以利用产生抽象。开发人员B肯定会关注 小部件如何做它所做的事情。

TLDR;

  • 抽象 - 我关心 的内容,但不关心 它是怎么做的。
  • 封装 - 我关心 如何执行它所做的事情,以便其他人只需要关心它做什么

(作为一个松散的概括,要抽象一些东西,你必须封装其他东西。通过封装某些东西,你已经创建了一个抽象。)

答案 14 :(得分:1)

抽象的意见不是隐藏实现或背景细节的意思!

抽象为我们提供了处理现实世界的表现的好处,它更容易处理,具有重用的能力,可以与我们或多或少复杂的程序包的其他组件结合使用。因此,我们必须找出how我们选择现实世界的完整和平,这足以表示我们的算法和数据的意义。界面的实现可能会隐藏细节,但这不是我们为抽象内容所做的工作的一部分。

对我来说,抽象最重要的是:

  1. 降低复杂性
  2. 减小尺寸/数量
  3. 将非相关域拆分为明确且独立的组件
  4. 这一切对我来说与隐藏背景细节无关!

    如果您考虑对某些数据进行排序,抽象可能会导致:

    1. 排序算法,独立于数据表示
    2. 比较函数,它独立于数据和排序算法
    3. 通用数据表示,与所使用的算法无关
    4. 所有这些都与隐藏信息无关。

答案 15 :(得分:0)

就iOS而言,可以说Objective C文件(即.h和.m)使用抽象和封装。

<强>抽象

头文件(.h)仅将函数和公共成员公开给外界。除非他们有实现文件,否则没有人知道它们是如何被使用的。它是.m文件,它自带了所有的使用和实现逻辑。 &#34;实施仍未曝光&#34;。

<强>封装

属性(@property)封装了iVar的内存管理属性(原子,强,保留,弱)。

答案 16 :(得分:0)

程序主要有两部分:DATA和PROCESS。抽象隐藏了进程中的数据,以便任何人都无法改变。封装将数据隐藏在任何地方,以便无法显示。 我希望这能澄清你的疑问。

答案 17 :(得分:0)

封装主要有两个原因:

1。)数据隐藏&amp;保护(您的班级用户除了通过您提供的方法外,不能修改数据)。

2.)将用于操纵数据的数据和方法组合成一个实体(胶囊)。 我认为第二个原因是你的面试官想要听到的答案。

另一方面,需要抽象以仅向用户公开所需信息,并隐藏不需要的细节(例如,隐藏方法的实现,以便用户不受影响,如果实施改变了。)

答案 18 :(得分:0)

在我看来,这两个术语在某种意义上是相关的,并且彼此混合在一起。 “封装”提供了一种对相关字段进行分组的方法,类(或模块)中的方法将相关事物包装在一起。从那时起,它以两种方式提供数据隐藏;

  1. 通过访问修饰符。

    纯粹用于隐藏类/对象的状态。

  2. 摘要一些功能。

    一个。通过接口/抽象类,封装类或模块内的复杂逻辑可以被抽象化/推广以供外部使用。

    湾通过功能签名。是的,甚至是功能签名抽象的例子。因为调用者只知道签名和参数(如果有的话),并且对函数的执行方式一无所知。它只关心返回的价值。

  3. 同样,“抽象”可能会考虑将行为分组/包装到接口(或抽象类或甚至可能是普通类)中的封装方式。

答案 19 :(得分:0)

关于抽象的基本要素是客户端代码根据不同的逻辑/抽象模型进行操作。这个不同的模型可能比实现恰好在任何给定的客户端使用中更复杂或更少

例如,“Iterator”抽象(也称为概括)对0或更多值的顺序遍历 - 在C ++中它表现为begin()* / ->(解除引用),{{ 1}},预先/后end()以及可能++,然后有--++=[]等。这是一个如果客户端可以说在阵列中增加std::advance,那么行李很多。重要的是抽象允许需要执行这种遍历的客户端代码与提供元素的“容器”或数据源的确切性质分离。迭代是一种更高级别的概念,有时会限制遍历的执行方式(例如,前向迭代器一次只能推进一个元素),但数据可以由更大的一组源提供(例如从键盘中提供)在并发存储的值的意义上甚至没有“容器”)。客户端代码通常可以切换到通过自己的迭代器抽象的另一个数据源,只需要很少甚至没有更改,甚至可以多态地转换为其他数据类型 - 隐式或显式地使用std::iterator_traits<Iterator>::value_type可用的东西。

这与封装完全不同,封装是使某些数据或函数不易访问的做法,这样您就知道它们只是作为公共接口上的操作而间接使用的。封装是在对象上维护不变量的重要工具,这意味着您希望在每次公共操作后保持真实 - 如果客户端代码只能到达并修改您的对象,那么您就无法执行任何操作不变量。例如,一个类可能会包装一个字符串,确保在任何操作之后,任何小写字母都被更改为大写,但如果客户端代码可以到达并在字符串中放入一个小写字母而不涉及类的成员函数,那么无法执行不变量。

要进一步突出显示差异,请考虑说一个size_t private数据成员,该成员偶然由对包含对象的操作填充,并在销毁时丢弃报告。由于数据和析构函数的副作用没有以任何方式与对象的客户端代码交互,并且对象上的操作不是故意控制计时行为,因此没有抽象的时间报告功能,但有封装。抽象的一个例子是将时序代码移动到一个单独的类中,该类可能封装std::vector<Timing_Sample>(使其成为vector)并只提供privateadd(const Timing_Sample&)之类的接口。 - 使用此类工具所涉及的必要逻辑/抽象操作,以及非常理想的副作用,即抽象代码通常可以重用于具有类似功能需求的其他客户端代码。

答案 20 :(得分:0)

抽象:隐藏数据。 封装:绑定数据。

答案 21 :(得分:0)

为什么要封装?为什么要抽象?

让我们从以下问题开始:

1)如果我们允许代码直接访问字段怎么办? (直接允许将字段设为公开

让我们通过一个例子来理解这一点,

following is our BankAccount class and following is its limitation
*Limitation/Policy* : Balance in BankAccount can not be more than 50000Rs. (This line 
 is very important to understand)

class BankAccount
{
   **public** double balanceAmount;
}

Following is **AccountHolder**(user of BankAccount) class which is consumer of 
**BankAccount** class.

class AccountHolder
{
   BankAccount mybankAccount = new BankAccount();

   DoAmountCreditInBankAccount()
   {
       mybankAccount.balanceAmount = 70000; 
      /* 
       this is invalid practice because this statement violates policy....Here 
       BankAccount class is not able to protect its field from direct access
       Reason for direct access by acount holder is that balanceAmount directly 
       accessible due to its public access modifier. How to solve this issue and 
       successfully implement BankAccount Policy/Limitation. 
      */
   }
}

如果代码的其他部分直接访问balanceAmount字段并将余额金额设置为70000Rs,这是不可接受的。在这种情况下,我们不能阻止代码的其他部分访问balanceAmount字段。

那我们能做什么?

=>答案是我们可以将balanceAmount字段设为私有,以便其他任何代码都不能直接访问它,并且只能通过对balanceAmount字段进行操作的公共方法来访问该字段。方法的主要作用是我们可以在方法内部编写一些预防逻辑,以使字段不能使用超过50000Rs进行初始化。在这里,我们在称为balanceAmount的数据字段和对该字段进行操作的方法之间进行绑定。此过程称为封装。(这全都涉及使用访问修饰符(例如private)保护字段)

封装是实现抽象的一种方法。但是如何? =>此方法的用户将不知道他/她将调用的方法的实现(如何记入金额?逻辑和所有其他东西)。不了解用户的实现细节称为抽象(隐藏用户的细节)。

Following will be the implementation of class:

class BankAccount
{
   **private** double balanceAmount;

   **public** void UpdateBankBalance(double amount)
   {
    if(balanceAmount + amount > 50000)
    {
       Console.WriteLine("Bank balance can not be more than 50000, Transaction can 
                          not be proceed");
    }
    else
    {
       balanceAmount = balanceAmount + amount;
           Console.WriteLine("Amount has been credited to your bank account 
                              successfully.....");
    }
   }
}


class AccountHolder
{
   BankAccount mybankAccount = new BankAccount();

   DoAmountCreditInBankAccount()
   {
      mybankAccount.UpdateBankBalance(some_amount);
      /*
       mybankAccount.balanceAmount will not be accessible due to its protection level 
       directly from AccountHolder so account holder will consume BankAccount public 
       method UpdateBankBalance(double amount) to update his/her balance.
      */
   }
}

答案 22 :(得分:0)

封装基本上是拒绝访问内部实现或外部世界有关内部的知识,而抽象则给出了有助于外部实现的任何实现的概括视图与之互动的世界

答案 23 :(得分:0)

简单地说,抽象就是使与对象交互的必要信息可见,而封装使开发人员能够实现所需的抽象级别。