抽象和封装有何不同?

时间:2013-06-05 11:25:03

标签: c# oop encapsulation abstraction

我正准备接受采访并决定刷新我的OOP概念。 有数百篇文章可供使用,但似乎每篇文章都有不同的描述。 Some

  

抽象是“识别具有的常见模式的过程   系统变化;抽象代表了共同的模式   并提供了一种指定使用哪种变体的方法“(理查德   加布里埃尔)。

并通过抽象类实现。

有些other

  

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

  

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

我一遍又一遍地搜索,结果似乎都没有给我一个正确的答案。 现在,封装在哪里适合所有这些? 我搜索了一下stack overflow question。即使这些问题的答案也令人困惑 Here,它说

  

封装是一种用作抽象的一部分的策略。封装   指对象的状态 - 对象封装它们的状态和   把它从外面隐藏起来;班级的外部用户与之互动   通过它的方法,但不能直接访问类状态。所以   该类抽象出与其相关的实现细节   状态。

here另一位知名成员说,

  

它们是不同的概念。

     

抽象是精炼所有人的过程   对象的不需要/不重要的属性,只保留   最适合您所在领域的特征。

现在我搞砸了整个概念。我知道抽象类,继承,访问说明符和所有。我只是想知道当我被问及抽样和/或封装时我应该如何回答。

请勿将其标记为重复。我知道有几个类似的问题。但我想避免相互矛盾的解释之间的混淆。任何人都可以提出可靠的链接吗?除非再次造成混淆,否则也欢迎链接到stackoverflow问题。 :)

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

13 个答案:

答案 0 :(得分:92)

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

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

答案 1 :(得分:44)

  

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

实际上那就是封装。还可以看到维基百科文章的第一部分,以免被封装和数据隐藏混淆。 http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)

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

这里有一篇很好的文章。 http://blog.ploeh.dk/2012/11/27/Encapsulationofproperties/ 另请参阅该文章中链接的文章。

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

你进行封装以降低复杂性。

  

抽象是识别具有系统变化的常见模式的过程。抽象表示共同模式,并提供指定使用哪种变体的方法。 (理查德加布里埃尔)。

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

  

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

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

如果您遇到实际问题并提供特定解决方案,则可以使用抽象来形式化更通用的解决方案,该解决方案还可以解决具有相同常见模式的更多问题。这样,您可以增加组件的可重用性,或者使用为同一域甚至不同域制作的其他程序员制作的组件。

很好的例子是.net框架提供的类,例如list或collection。这些是非常抽象的类,几乎可以在任何地方和许多领域中使用。想象一下,如果.net只实现了一个EmployeeList类和一个只能保存具有特定属性的员工和公司列表的CompanyList。在很多情况下,这样的课程将毫无用处。如果你不得不重新实现CarList的整个功能,那会是多么痛苦。那么" List"摘自员工,公司和汽车。 List本身是一个抽象的概念,可以由它自己的类实现。

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

你做抽象以提供可重用性。

答案 2 :(得分:43)

Abstraction & Encapsulation Example <子> Image source

抽象:由猫的左上角和右上角图像勾勒出来。外科医生和老太太以不同的方式设计(或可视化)动物。同样,您可以在Cat类中添加不同的功能,具体取决于应用程序的需要。每只猫都有肝脏,膀胱,心脏和肺,但是如果你需要你的猫来咕噜咕噜叫只有,你会将你的应用程序的猫抽象到左上角而不是右上角的设计中。

封装:由站在桌子上的猫概述。那个猫外面的每个人应该把猫视为。他们不必担心猫的实际实施是左上角还是右上角,甚至是两者的组合。

PS: 在同一问题上转到here,听听完整的故事。 < / p>

答案 3 :(得分:25)

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

  • 将数据和功能整合到一个单元中(称为 class)被称为封装。包含和隐藏的封装 有关对象的信息,例如内部数据结构和 代码。

封装是 -

  • 隐藏复杂性,
  • 将数据和功能绑定在一起,
  • 制作复杂方法的私有,
  • 将实例变量设为私有
  • 隐藏最终用户不必要的数据和功能。

封装实现抽象。

抽象是 -

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

让我们看一个例子 -

下面的图片显示了一个GUI&#34;要添加到数据库中的客户详细信息&#34;。

Customer Screen GUI

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

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

  
      
  • 存储客户代码和客户名称的2个变量。

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

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

现在只有ADD方法不能单独使用。

步骤-2:验证将如何运作,ADD功能如何?

我们需要数据库连接代码和验证码(额外方法)。

     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() [复杂和额外方法])。用户只需要查看并了解客户代码,客户名称和添加按钮,它将添加记录。最终用户不关心如何将数据添加到数据库?

第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步:私有化并不涉及最终用户互动的额外且复杂的方法是封装

<强> P.S。 - 上面的代码很难而且很快。

更新: 此链接上有一个视频来解释样本: What is the difference between Abstraction and Encapsulation

答案 4 :(得分:9)

我认为它们的概念略有不同,但通常它们是一起应用的。封装是一种隐藏调用者实现细节的技术,而抽象更多的是一种设计理念,涉及创建类似于熟悉的对象/进程的对象,以帮助理解。封装只是可用于创建抽象的众多技术之一。

例如,选择“windows”。它们不是传统意义上的窗户,它们只是屏幕上的图形方块。但将它们视为窗口是有用的。这是一种抽象。

如果“windows API”隐藏了文本或图形在窗口边界内的物理渲染方式的详细信息,那就是封装。

答案 5 :(得分:6)

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

  • 抽象:表示您只包含设计中所需的实体功能。因此,如果每个银行帐户都有一个开放日期,但您的申请并不需要知道帐户的开放日期,那么您只需添加 OpeningDate 字段即可您的面向对象的BankAccount类设计。 OOAD中的抽象与编程中的抽象类无关。通过这个原则,您的实体是抽象他们实际上是什么。您将银行帐户的抽象设计为仅满足您的应用程序所需的详细程度。

  • 继承:更像是一个技巧而非实际原则,这使您无需重写您在其他地方编写的功能。唯一的问题是,您正在编写的新代码与您想要重用的旧代码之间必须存在关系。就像你可以继承你的父母一样。财富,您可以从父类继承字段和方法。因此,获取父类所拥有的所有东西,然后在需要时添加更多内容,就是继承。不要在面向对象设计中寻找继承。继承将出现。

  • 多态性:是继承的结果。从父级继承方法很有用,但是如果情况需要,能够修改方法是多态的。您可以在子类中使用与父类完全相同的签名实现一个方法,以便在调用时,执行子类中的方法。这是多态性。

  • 封装:意味着将相关功能捆绑在一起,并且只能访问所需的功能。这个原则是在面向对象设计中设计类的基础,其中:

    • 您将相关数据和方法放在一起;和,
    • 并非所有数据和方法都可以公开。

另一个简化的答案是here

认为&#34; OOAD的抽象导致OOP的抽象关键字&#的人34; ...... 那就是不正确

示例:当您使用面向对象原则在应用程序中设计大学时,您只需设计一个&#34;抽象&#34;大学尽管几乎每所大学通常都有一台自动取款机,但如果您的申请不需要,您可能不会加入这一事实。现在虽然您只设计了大学的抽象,但您不需要在课堂声明中加入 abstract 。您的大学抽象设计将成为您申请中的正常课程。

答案 6 :(得分:4)

my 2c

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

答案 7 :(得分:2)

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

答案 8 :(得分:1)

封装:隐藏实现细节(注意:数据和/或方法),使得只有外部可读/可写/可用的内容才能被他们访问,其他所有内容都是“不可触及的”。

抽象:这有时特指一种无法实例化的类型,它通常通过子类化为其他类型提供模板。更一般地说,“抽象”是指制作/拥有不太详细,不太具体,不那么精细的东西。

概念之间存在一些相似性,重叠,但记住它的最佳方式是这样的:封装更多地是关于隐藏细节,而抽象更多是关于概括细节。

答案 9 :(得分:1)

抽象和封装是令人困惑的术语,并且相互依赖。 让我们举一个例子:

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

当您创建Person类时,您通过将属性和函数一起编写(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;
            }
        }

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

答案 10 :(得分:0)

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

抽象是自己的课堂设计。

意味着,你如何创建你的类树,哪些方法是通用的,哪些方法是继承的,可以被覆盖,哪些属性只在私有层上,或者在受保护的方面,你如何构建你的类继承树,Do您使用final类,abtract类,接口实现。

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

答案 11 :(得分:0)

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

抽象与“为什么”我首先将其封装起来有关。

我基本上是在告诉客户“你不需要了解我如何处理付款和计算运费等等。我只是想让你告诉我你要'结帐'我会照顾详细信息。“

这样我通过将(抽象)概括为Checkout请求来封装细节。

我真的认为抽象和封装是一体的。

答案 12 :(得分:0)

抽象

在Java中,抽象意味着将信息隐藏到现实世界中。它建立了当事人之间的合同,告诉我们“我们应该如何利用服务”。

示例,在API开发中,只向全世界展示了服务的抽象信息,而不是实际的实现。 java中的接口可以很好地帮助实现这个概念。

接口提供各方之间的合同,例如,生产者和消费者。生产者在不知道消费者如何制造产品的情况下生产商品。但是,通过界面,Producer让所有消费者都知道什么产品可以买到。在抽象的帮助下,生产者可以将产品推销给消费者。

封装:

封装是抽象的一个层次。同一产品公司尝试屏蔽彼此生产组的信息。例如,如果一家公司生产葡萄酒和巧克力,封装有助于屏蔽每种产品彼此之间的信息。

  1. 如果我有一个葡萄酒包装,另一个包装 巧克力,如果所有类都在包中声明为 默认访问修饰符,我们提供包级别封装 适用于所有课程。
  2. 在一个包中,如果我们声明每个类(成员字段)为 这种方式私有,并有一个公共方法来访问这些字段 给这些字段提供类级封装