了解封装和抽象的简单方法


73

学习特别感兴趣的OOP概念,以深入了解抽象和封装。

已经检查了以下内容

抽象VS信息隐藏VS封装

和封装之间的区别?

我发现很难用一个真实而简单的示例类/代码片段来理解这些概念。

我的一位同事说,抽象只不过是创建抽象类和使用范围保护其成员变量的普通类,称为封装。

有没有一种简单的方法可以使我理解并帮助他人了解他们的确切身份,而不是重复以下内容?

抽象和封装是互补的概念:抽象集中于对象的可观察行为...封装着重于引起这种行为的实现...封装通常是通过信息隐藏来实现的,信息隐藏是隐藏所有对象的过程。对物体的本质没有帮助的秘密。


您对该描述感到困惑的是什么?
约瑟夫·曼斯菲尔德

1
顺便说一句,为什么一切都必须简单?
gdoron支持Monica

1
抽象是抽象,但封装与抽象无关,它的意思是将数据和用于管理此数据的逻辑保存在同一对象(类)中,
Serghei 2013年

@sftrabbit,我无法理解该类的可观察行为,即我们所说的引起这种行为的抽象和实现?
Billa

Answers:


171

抽象是一个过程,其中您仅显示来自用户的“相关”数据和“隐藏”对象的不必要的详细信息。考虑一下您的手机,您只需要知道要发送消息或拨打电话时要按下的按钮,按下按钮时会发生什么情况,消息的发送方式,呼叫的连接方式都与抽象无关。用户。

封装是将数据和功能组合到称为类的单个单元中的过程。在封装中,不直接访问数据。可通过类内部提供的函数进行访问。用简单的话来说,该类的属性将保持私有状态,并提供公共的getter和setter方法来操纵这些属性。因此,封装使数据隐藏的概念成为可能。

在此处输入图片说明


1
“ ...仅显示“相关”数据而“隐藏”不必要的细节...”,抽象说明中的“数据”一词可能会有些欺骗,因为抽象更多地是仅表示相关功能(如果您愿意, )。这一点得到了手机示例及其功能

所包含的图像给出了关于什么是一个很好的主意,尽管=)

您还可以添加的C#示例对于abstraction使用抽象类和接口等,喜欢的藏身实施检查
Shaijuŧ

28

抽象是隐藏信息或仅向客户端提供必要的详细信息。

例如汽车制动器-您只知道踩踏板会停止车辆,但是您不需要知道它在内部如何工作。

抽象的优点明天,如果制动实现从鼓式制动改为盘式制动,作为客户,您无需更改(即您的代码不会更改)

封装将数据和行为绑定在一个单元中。这也是一种用于限制对某些组件的访问的语言机制(这可以通过访问修饰符(例如private,protected等)来实现)

例如,具有属性(即数据)和行为(即,对该数据进行操作的方法)


这意味着我们从概念上理解了抽象,而不是abstract为方法或类定义关键字。正确?
Billa

2
正确。OOP是哲学和语言中立的。
Jaydeep Rajput 2013年

1
封装的一个很好的例子是使用Getter和Setter时。您可以通过Setter方法将值分配给类(对象)实例的私有属性(例如,setName("john")wheresetName(firstName)是一个公共方法,而其中_firstName = firstNamewhere_firstName是私有属性)。

2
或者,...封装是实现抽象的一种方式?
安德鲁(Andrew)

最好的解释
林托·乔治

13

使用C#的示例

//abstraction - exposing only the relevant behavior
public interface IMakeFire
{
     void LightFire();
}

//encapsulation - hiding things that the rest of the world doesn't need to see
public class Caveman: IMakeFire
{
     //exposed information  
     public string Name {get;set;}

     // exposed but unchangeable information
     public byte Age {get; private set;}

     //internal i.e hidden object detail. This can be changed freely, the outside world
     // doesn't know about it
     private bool CanMakeFire()
     {  
         return Age >7;
     }

     //implementation of a relevant feature
     public void LightFire()
     {
        if (!CanMakeFire())
        {
           throw new UnableToLightFireException("Too young");
        }
        GatherWood();
        GetFireStone();
        //light the fire

     }

     private GatherWood() {};
     private GetFireStone();
}

public class PersonWithMatch:IMakeFire
{
      //implementation
 }

任何穴居人都可以生火,因为它实现了IMakeFire“功能”。如果有一群造火机(清单),则意味着Caveman和PersonWithMatch都是有效的选择。

这意味着

  //this method (and class) isn't coupled to a Caveman or a PersonWithMatch
  // it can work with ANY object implementing IMakeFire
  public void FireStarter(IMakeFire starter)
  {
        starter.LightFire();
    }

因此,您可以有许多实现者,这些实现者具有许多详细信息(属性)和行为(方法),但是在这种情况下,重要的是它们的起火能力。这是抽象的。

由于生火需要一些步骤(GetWood等),因此这些是隐藏的,因为它们是类的内部问题。穴居人还有许多其他可以被外界称为的公共行为。但是某些细节始终会被隐藏,因为它们与内部工作有关。它们是私有的,仅针对对象而存在,从不公开。这是封装


9

抽象是广义术语。即封装是抽象的子集。

抽象是管理复杂系统的强大方法。抽象由定义明确的对象及其分层分类来管理。

例如,汽车本身就是一个定义明确的对象,它由齿轮传动系统,转向机构,发动机等其他几个较小的对象组成,它们又具有自己的子系统。但是对于人类来说,汽车是一个单一的对象,即使其内部细节未知,也可以借助其子系统进行管理。 礼貌


封装形式:将数据成员和方法包装在一起成为一个单元(即类),称为封装。

封装就像封装在胶囊中。那就是将与一个对象有关的相关操作和数据封装到该对象中。

封装就像您可以存放笔,书等的袋子一样。这意味着这是封装成员和功能的属性。

class Bag{
    book;
    pen;
    ReadBook();
}

封装意味着隐藏对象的内部细节,即对象如何执行某些操作。

封装可防止客户端看到其内部视图,在该视图中实现了抽象的行为。

封装是一种用于保护一个对象中的信息免受其他对象攻击的技术。

为了安全起见,隐藏数据,例如将变量设为私有,并公开该属性以访问将公开的私有数据。

因此,当您访问属性时,可以验证数据并进行设置。 礼貌


5

好吧,我将用一个真实的例子来解释抽象。假设您的房子中确实有电插头,并且许多设备可以连接到同一插头,但是插头永远不会知道它连接的设备,换句话说,设备的详细信息被抽象(隐藏)到了插头中。

想想如果我们不使用插头将设备直接连接到电线怎么办?说将灯泡直接连接到电线,然后电线知道它连接到哪个设备,并且每当需要更换灯泡时,我们都必须从灯泡上断开电线连接,这意味着灯泡与电线紧密耦合。换句话说,灯泡和电线知道其连接到的细节,意味着没有抽象。

在面向对象的世界中,抽象的工作原理完全相同。使用其他类的函数/属性的类不需要知道它正在使用哪个类的函数/属性,因此应该使用接口/抽象类来抽象所有内容。

让我编写相同的示例。在这里,我有一个“ ElectricPlug”类,它正在运行设备。但是“ ElectricPlug”类不知道它在运行哪个设备。它可以是实现“ IDevice”接口的任何类,这意味着“ RunDevice”的实现是从“ ElectricPlug”中抽象出来的。这是完整的示例代码,

class Program
{
    static void Main(string[] args)
    {
        ElectricPlug electricPlug = new ElectricPlug(new Bulb());
    }
}

public class ElectricPlug
{
    private readonly IDevice _device;
    public ElectricPlug(IDevice device)
    {
        _device = device;
    }

    public void Run()
    {
        _device.Rundevice();
    }
}


public interface IDevice
{
    void Rundevice();
}


public class Bulb : IDevice
{
    public void Rundevice()
    {
       Console.WriteLine("Switched on bulb");
    }
}

4

抽象是您从计划中捕获/表示的实体中“丢弃”不必要的细节并仅保留与您的域相关的实体属性的过程。
例如:代表汽车,您将保留例如型号和价格,当前位置和当前速度,而忽略颜色和座位数等。

封装是属性和在单个抽象单元(即类)中对它们进行操作的操作的“绑定”。
因此,汽车将具有accelarate stop操纵位置和当前速度等的功能。


5
似乎抽象是一种概念上的理解,abstract我想与关键字无关。
Billa

4

抽象是隐藏细节以简化界面的一种方法。

因此,以汽车为例,汽车中的所有控件都是抽象的。这使您可以在不了解转向,加速或减速系统的基本细节的情况下操作车辆。

一个好的抽象是跨相似问题的多个实例广泛地标准化接口的抽象。一个伟大的抽象可以改变一个行业。

现代方向盘,制动踏板和油门踏板都是很好的抽象示例。汽车转向最初看起来更像是自行车转向。制动器和油门都是手动操作的。但是,我们今天使用的抽象是如此强大,席卷了整个行业。

-

封装是一种隐藏细节的方法,目的是防止细节受到外界操纵。

密封防止驾驶员操纵汽车的行驶方式-从转向,悬架和制动的刚度,到油门和变速器的特性。大多数汽车不提供用于更改任何这些东西的接口。这种封装确保车辆将按照制造商的预期运行。

有些汽车提供了少数几种驾驶模式,例如豪华,运动和经济驾驶模式,这些模式使驾驶员可以同时更改其中一些属性。通过提供驾驶模式,制造商允许驾驶者对体验进行某种控制,同时阻止他们选择会使车辆变得不那么令人愉悦或不安全的属性组合。这样,制造商隐藏了细节以防止不安全的操作。这是封装。


坦白地说,这是我读过的最好的答案之一...我仍然不明白为什么它有2票赞成。我已将答案
赞成

3

封装听起来很像,是一种将盒子放在物体周围以保护其内容的方法。抽象是提取某些东西的功能特性,这样您就可以仅使用提取的内容执行操作,而无需了解内部工作原理。

当我们说两种物质是液体时,我们使用“液体”作为对我们选择讨论的那些物质的特性的抽象。鉴于我们以前在液体中的经验,这种抽象告诉我们可以使用这些物质做什么。

抽象也确实与层次结构没有任何关系。您可以使用“金属”之类的另一种抽象,以不同的方式提取物质的特性。

抽象会忘记细节,因此,如果您使用的是特定的抽象,则不应询问抽象未授予的基础物质的属性。就像您要喝牛奶和水并将它们混合在一起一样,您会很难过,然后问您有多少牛奶。

函数是对具有映射概念的事物的抽象,也就是说,您可以在函数的内部内容上运行一个函数,该函数会将内部位转换为其他任何位。外在的东西保持不变。

有用的地方是,如果您有一个可以在Lists上使用的函数,并且意识到仅依赖于map接口,则可以依赖Functor,然后该函数就可以使用流,promise,mays,tuple和其他具有该抽象性的东西。

诸如Haskell之类的功能语言具有非常强大的抽象能力,这些能力使极端的代码重用变得切实可行。


2

抽象就像使用计算机。

除了通过GUI(图形用户界面)和外部硬件(例如屏幕)看到的内容外,您完全不知道它的作用。所有那些漂亮的颜色等等。您只会看到与您作为普通消费者有关的详细信息。

封装隐藏不相关细节的实际行为。

您使用的是计算机,但看不到其CPU(中央处理器)的外观(除非尝试插入该计算机)。它被隐藏(或封装)在所有铬和塑料后面。

在OOP(面向对象编程)语言的上下文中,通常具有这种设置:

CLASS {
  METHOD { 
    *the actual code*
  }
}

“封装”的示例将具有普通用户看不到的(私有)方法。“抽象”是指常规用户,他们可以(公共)使用方法来使用私有对象。


1

数据抽象:访问任何类的数据成员和成员函数简称为数据抽象...

封装:绑定变量和函数或1可以说单个成员中的数据成员或成员函数一起称为数据封装...。


1

封装可以看作是包装纸,用于将数据绑定在一起并作为一个整体起作用,从而保护其免受各种外部污垢的侵扰(我的意思是外部功能)。

抽象涉及细节的缺乏和使用简单接口来控制复杂系统。

例如,我们可以通过按按钮来点亮灯泡,而无需担心基础的电气工程(抽象)。

但是,您无法以其他任何方式点亮灯泡。(封装)


0
public abstract class Draw {
    public abstract void drawShape(); // this is abstraction.  Implementation detail need not to be known.
    // so we are providing only necessary detail by giving drawShape(); No implementation. Subclass will give detail.


    private int type;    // this variable cannot be set outside of the class. Because it is private.
    // Binding private instance variable with public setter/getter method is encapsulation 

    public int getType() { 
        return type;
    }

    public void setType(int type) {  // this is encapsulation. Protecting any value to be set.
        if (type >= 0 && type <= 3) {
            this.type = type;
        } else {
            System.out.println("We have four types only. Enter value between 0 to 4");
            try {
                throw new MyInvalidValueSetException();
            } catch (MyInvalidValueSetException e) {
                e.printStackTrace();
            }

        }
    }
}

Abstraction与不知道实现细节的方法有关,这是一种实现隐藏。
Encapsulation与实例变量与方法的绑定有关,方法是一种数据隐藏。


可以更改type实现者中的值,因为实现者类将提供实现
Billa 2013年

@Billa我在评论中不明白您的问题。
AmitG

从具体类中,我可以设置或更改type抽象类中定义的变量的值吗?为什么具体的类不能更改,因为它提供了实际的实现?
Billa 2013年

私有变量type在具体的类中不可继承,因为它是私有的。但是您可以type通过setType()从具体类中调用方法来设置变量。但是我们无法根据需要设置任何值。如果我们允许公众访问,type则可以type使用特定范围值来设置限制值。因此,这种方法/设计是封装。
AmitG

0

数据抽象:DA只是过滤具体项目。通过类,我们可以实现纯抽象,因为在创建类之前,我们只能考虑与类有关的信息。

封装:这是一种机制,通过它我们可以保护我们的数据免受外界攻击。


0

抽象是向用户显示必要的信息,其中封装是向用户隐藏不需要的数据(来自用户的产品)。

封装实现抽象。

抽象是封装实际实现的过程。 例如 添加用户逻辑->我们需要验证用户,创建数据库连接并插入用户。因此,用户不知道首先需要调用validate函数,创建数据库连接然后在数据库中插入值。他只调用AddUser函数,该函数使用in来内部调用所有逻辑,这只是封装(将功能分组并隐藏方法)。


嗨,欢迎来到Stack Overflow。当回答已经有很多答案的问题时,请确保对您提供的回答为何具有实质性,而不是简单地呼应原始张贴者已经审查过的内容,增加一些其他见解。这个问题有14个答案所有这些都表明了通过投入时间为网站做出贡献的愿望以及原始海报的理解。您的贡献没有任何表现。
chb

0

封装:我认为这与如何将事物绑定到一个实体而不是隐藏有很大关系。如果您选择隐藏某物,则可以。

抽象:抽象与隐藏的东西有很大关系,并且抽象的层次可能不同。例如,在功能抽象中,我们可能会说能够将项目添加到列表很重要,但是如何实现的细节并不令人关注,应该将其隐藏。使用数据抽象,我们可以说列表是我们可以存储信息的地方,但是列表的实际实现方式(例如,作为数组或一系列链接的位置)并不重要,应该隐藏。

参考


0

抽象-简单的抽象可以说是一种让用户远离某些系统的复杂细节或详细工作的方法。您也可以假定它是在设计和接口级别解决任何问题的简单方法。

您可以说抽象的唯一目的是隐藏可能会使用户感到困惑的细节。因此,为简化起见,我们可以使用抽象。抽象还是面向对象编程的概念。它隐藏了实际数据,仅显示必要的信息。例如,在ATM机中,您不知道它在内部如何工作。只有您关心使用ATM接口。因此,可以将其视为一种抽象过程。

封装-封装也是面向对象编程的一部分。在这种情况下,您要做的就是将数据和代码打包在一起,以便它们可以作为一个单元工作。它在实现级别上起作用。它还可以提高应用程序的维护性。

封装着重于将保存信息的过程。在这里,您必须保护数据免受外部使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.