抽象和封装如何不同?

我正在准备采访,并决定刷新我的面向对象的概念。 有数百篇文章,但似乎每个人都有不同的描述。 有人说

抽象是“识别具有系统变化的常见模式的过程;抽象代表了常见模式,并提供了指定使用哪种变化的手段”(Richard Gabriel)。

并通过抽象类来实现。

其他人说

抽象意味着只向对象的客户显示必要的细节

假设您的Employee类中有一个“CalculateSalary”方法,它将EmployeeId作为参数,并将当前月份的员工工资作为整数值返回。 现在,如果有人想要使用这种方法。 他不需要关心Employee对象如何计算工资? 他唯一需要关注的是方法的名称,input参数和结果成员的格式,

我一遍又一遍地search,结果似乎没有给我一个正确的答案。 现在,封装在哪里都适合? 我search,发现一个堆栈溢出的问题 。 即使这个问题的答案是混淆在这里 ,它说

封装是一种用作抽象的一部分的策略。 封装是指对象的状态 – 对象封装它们的状态并将其隐藏起来; 类的外部用户通过它的方法与它交互,但不能直接访问类的状态。 所以这个类抽象出与其状态相关的实现细节。

另外一位知名的成员说,

他们是不同的概念。

抽象是细化一个对象的所有不必要/不重要的属性,只保留最适合你的领域的特征的过程。

现在我搞砸了整个概念。 我知道抽象类,inheritance,访问说明符和所有。 我只想知道在面试中被问及抽象和/或封装的时候应该如何回答。

请不要将其标记为重复 。 我知道有几个类似的问题。 但是我想避免相互矛盾的解释之间的混淆。 任何人都可以build议一个可信的链接? 链接到stackoverflow问题也是受欢迎的,除非它再次造成混乱。 🙂

编辑:我需要答案,有点面向c#

抽象意味着只向对象的客户显示必要的细节

其实这是封装。 也看到维基百科文章的第一部分,以不被封装和数据隐藏混淆。 http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming);

请记住,通过简单地隐藏你所有的类成员1:1属性是不封装的。 封装就是保护不变式和隐藏实现细节。

这里有一篇很好的文章。 http://blog.ploeh.dk/2012/11/27/Encapsulationofproperties/还可以看看这篇文章中链接的文章。;

类,属性和访问修饰符是在c#中提供封装的工具。

你要封装以减less复杂性。

抽象是“识别具有系统变化的常见模式的过程;抽象代表了常见模式,并提供了指定使用哪种变化的手段”(Richard Gabriel)。

是的,这是抽象的一个很好的定义。

他们是不同的概念。 抽象是细化一个对象的所有不必要/不重要的属性,只保留最适合你的领域的特征的过程。

是的,他们是不同的概念。 请记住,抽象实际上是使对象适合您的域名的唯一对立面。 一般是为了使对象适合于域名!

如果您遇到实际问题并提供特定的解决scheme,则可以使用抽象来forms化更通用的解决scheme,也可以解决具有相同常见模式的更多问题。 通过这种方式,您可以提高组件的可重用性,或者使用其他程序员为同一个域或甚至不同域创build的组件。

好的例子是.net框架提供的类,例如列表或集合。 这些都是非常抽象的类,几乎可以在任何地方和很多领域使用。 想象一下,如果.net只实现了一个EmployeeList类和一个CompanyList,它只能包含具有特定属性的员工和公司列表。 这样的类在很多情况下是无用的。 例如,如果你不得不重新实现一个CarList的全部function,那将会是多么的痛苦。 因此,“名单”从员工,公司和汽车中抽离出来。 列表本身是一个抽象的概念,可以由自己的类来实现。

接口,抽象类或inheritance和多态是在c#中提供抽象的工具。

你做抽象为了提供可重用性。

封装 :使用getter和setter等隐藏数据

抽象 :使用抽象类和接口隐藏实现

抽象与封装示例 图像源

抽象:由猫的左上angular和右上angular图像概述。 外科医生和老太太devise(或可视化)动物的方式不同。 同样,根据应用程序的需要,您可以在Cat类中添加不同的function。 每只猫都有肝脏,膀胱,心脏和肺脏,但是如果你只需要你的猫“呜呜”,你就会将你的应用程序的猫抽象到左上angular而不是右上angular。

封装:由站在桌子上的猫概述。 这就是猫以外的每个人都应该看到猫 。 他们不必担心猫的实际执行是左上angular还是右上angular,或者两者的组合。


PS:在这个同样的问题上来听听这个完整的故事。

我将尝试以简单的方式演示封装和抽象..让我们看看..

  • 将数据和函数封装成一个单元(称为类)称为封装。 封装包含和隐藏关于对象的信息,例如内部数据结构和代码。

封装是 –

  • 隐藏复杂性,
  • 将数据和函数绑定在一起,
  • 使复杂的方法的私人,
  • 使实例variables的私有,
  • 从最终用户隐藏不必要的数据和function。

封装实现抽象。

抽象是 –

  • 显示什么是必要的,
  • 数据需要从最终用户摘要,

让我们看一个例子 –

下图显示了“要添加到数据库中的客户详细信息”的GUI。

客户屏幕GUI

通过查看图片,我们可以说我们需要一个客户类。

步骤1:我的客户类需要什么?

  • 2个variables来存储客户代码和客户名称。

  • 1将客户代码和客户名称添加到数据库中的function。

  namespace CustomerContent { public class Customer { public string CustomerCode = ""; public string CustomerName = ""; public void ADD() { //my DB code will go here } 

现在只有ADD方法不会在这里单独工作。

第二步:validation工作,ADD函数将如何工作?

我们将需要数据库连接代码和validation代码(额外的方法)。

  public bool Validate() { //Granular Customer Code and Name return true; } public bool CreateDBObject() { //DB Connection Code return true; } class Program { static void main(String[] args) { CustomerComponent.Customer obj = new CustomerComponent.Customer; obj.CustomerCode = "s001"; obj.CustomerName = "Mac"; obj.Validate(); obj.CreateDBObject(); obj.ADD(); } } 

现在,不需要向最终用户显示额外方法( Validate() ; CreateDBObject() [复杂和额外方法])。最终用户只需要查看和了解客户代码,客户名称和添加button将添加该logging..最终用户不关心它将如何将数据添加到数据库?

步骤-3:隐藏不涉及最终用户交互的额外复杂方法。

因此,使复杂和额外的方法作为私人而不是公开(即隐藏这些方法)和删除obj.Validate(); obj.CreateDBObject(); 从主要课程我们实现封装。

换句话说,简化接口到最终用户是封装。

所以现在完整的代码如下所示 –

  namespace CustomerContent { public class Customer { public string CustomerCode = ""; public string CustomerName = ""; public void ADD() { //my DB code will go here } private bool Validate() { //Granular Customer Code and Name return true; } private bool CreateDBObject() { //DB Connection Code return true; } class Program { static void main(String[] args) { CustomerComponent.Customer obj = new CustomerComponent.Customer; obj.CustomerCode = "s001"; obj.CustomerName = "Mac"; obj.ADD(); } } 

总结:

步骤-1 :我的客户类需要什么? 是抽象的

步骤-3 :步骤-3:将不涉及最终用户交互的额外复杂方法私有化为封装

PS – 上面的代码是困难和快速的。

更新:这个链接上有一个video来解释样本: 抽象和封装有什么区别

我认为他们是略有不同的概念,但往往他们一起应用。 封装是从调用者隐藏实现细节的技术,而抽象更多的是devise理念,涉及创build类似于熟悉的对象/过程的对象,以帮助理解。 封装只是许多可用于创build抽象的技术之一。

例如,拿“窗户”。 它们不是传统意义上的窗户,它们只是屏幕上的graphics方块。 但把它们想象成窗口是有用的。 这是一个抽象。

如果“windows API”隐藏文本或graphics在窗口边界内的物理呈现细节,那就是封装。

在抽象的背景下,我总是提到一个例子。 汽车上的自动变速器和手动变速器。 手动变速箱隐藏了换档的一些工作,但是您仍然必须作为驾驶员进行离合和换档。 自动变速器封装了变速器的所有细节,即将其隐藏起来,因此是齿轮换档过程的更高抽象。

我的2c

封装的目的是为了隐藏你的类的用户的实现细节,例如,如果你内部保持在你的类中的std ::列表项,然后决定一个std :: vector会更有效,你可以改变这个没有用户关怀。 也就是说,与stl容器交互的方式是归功于抽象,列表和向量都可以使用类似的方法(迭代器)以相同的方式遍历。

封装:隐藏实现细节(注意:数据和/或方法),使得只有外部人员可以读取/写入/使用的东西才可以访问,而其他东西则直接“不可触摸”。

抽象(Abstraction):这有时特指一种不能被实例化的types,它为其他types提供模板,通常可以通过子类化。 更一般地说,“抽象”是指使得/具有不太详细的,不太具体的,不那么细化的东西。

概念之间有一些相似之处,但是记住它的最好方法是这样的:封装更多的是隐藏细节,而抽象更多的是关于细节的概括

面向对象的分析和devise(OOAD)实际上是基于四个原则。 他们是:

  • 抽象:意味着您只能将您devise中所需的实体function集成在一起。 因此,如果每个银行账户都有开始date,但您的应用程序不需要知道账户的开户date,那么您不需要在BankAccount类的面向对象devise中添加OpeningDate字段。 OOAD中的抽象与编程中的抽象类无关。 通过这个原则,你的实体是他们实际上的抽象 。 您devise一个银行帐户的抽象,只有您的应用程序需要的细节级别。

  • inheritance:这是一个原则,可以使您免于编写您可以从其他人那里获得的function。 就像你可以inheritance父母的财富一样,你可以inheritance你父母的领域和方法。 所以,如果需要的话,考虑父类的所有东西,然后添加更多的东西,就是inheritance。 不要在面向对象的devise中寻找inheritance。 inheritance将出现。

  • 多态性:是inheritance的结果。 从父项inheritance方法是有用的,但是如果情况需要,可以修改方法是多态的。 你可以在子类中实现一个与父类完全相同的方法,这样当被调用时,子类的方法将被执行。 这是多态性。

  • 封装:意味着将相关的function捆绑在一起, 允许访问需求。 这个原则是devise面向对象devise课程基础,其中:

    • 你把相关的数据和方法放在一起; 和,
    • 不是所有的数据和方法都可能是公开的。

认为“OOAD的抽象结果导致OOP的抽象关键字”的人……那是不正确的

例如:当你使用面向对象的原则在一个应用程序中devise一个大学时,你只能devise一个大学的“抽象”。 即使几乎每所大学通常都有一台自动取款机,但如果您的应用程序不需要,您可能不会纳入这一事实。 而现在,尽pipe你只devise了一个抽象的大学,你不需要把抽象的类放在声明中。 你的抽象的大学devise将是你的应用程序中的一个普通的类。

正如我所知,封装本身隐藏了类的数据,只有通过setter / getters才能访问它们,如果它们必须从外部访问的话。

抽象是本身的类devise。

意思是,你如何创build你的类树,哪些方法是一般的,是inheritance的,哪些可以重写,哪些属性只在私有层面上,或者受保护,你如何build立你的类inheritance树,你使用final类,抽象类,接口实现。

抽象更多地放在了devise阶段,而封装也进入了发展阶段。

我这样想,封装隐藏了一些事情的完成方式。 这可以是一个或多个动作。

抽象是关于“为什么”我把它封装在第一位。

我基本上是告诉客户“你不需要知道如何处理付款和计算航运等等。我只是想让你告诉我你要'结帐',我会照顾你的细节“。

通过这种方式,我已经通过将摘要(抽象)概括为签出请求来封装细节。

我真的认为抽象和封装在一起。

抽象和封装是混淆的术语,相互依赖。 我们来举个例子:

 public class Person { private int Id { get; set; } private string Name { get; set; } private string CustomName() { return "Name:- " + Name + " and Id is:- " + Id; } } 

在创buildPerson类时,通过一起编写属性和函数(Id,Name,CustomName)进行封装。 当你把这个类暴露给客户端时,你执行抽象

 Person p = new Person(); p.CustomName(); 

你的客户端不知道这个函数中的Id和Name。 现在,如果您的客户想要知道姓氏,而不打扰函数调用。 你可以通过在Person类中添加一个属性来进行封装。

 public class Person { private int Id { get; set; } private string Name { get; set; } private string LastName {get; set;} public string CustomName() { return "Name:- " + Name + " and Id is:- " + Id + "last name:- " + LastName; } } 

看,即使在类中添加了一个额外的属性,你的客户端也不知道你对你的代码做了什么。 这是你抽象的地方。