Answers:
这里的大多数答案都集中在OOP上,但是封装要早得多:
每个函数都是一个封装 ; 用伪代码:
point x = { 1, 4 }
point y = { 23, 42 }
numeric d = distance(x, y)
在这里,distance
封装了平面中两点之间(欧几里得)距离的计算:它隐藏了实现细节。这是封装,纯净而简单。
抽象是泛化的过程:采用具体的实现并将其应用于不同的(尽管有些相关)数据类型。抽象的经典示例是C的qsort
数据排序功能:
关于的事情qsort
是,它不关心排序的数据-实际上,它不知道排序的数据。而是,它的输入类型是无类型指针(void*
),它只是C所说的“我不在乎数据类型”(也称为类型擦除)。重要的一点是qsort
,无论数据类型如何,始终保持不变的实现。那唯一有改变的是比较功能,它不同于数据类型的数据类型。qsort
因此,期望用户将所述比较功能作为函数参数提供。
封装和抽象密切相关,因此您可以指出它们是真正不可分割的。出于实际目的,这可能是正确的。就是说,这不是抽象的封装:
class point {
numeric x
numeric y
}
我们封装了点的坐标,但是除了逻辑上将它们分组之外,我们没有实质性地将它们抽象掉。
这是一个非封装的抽象示例:
T pi<T> = 3.1415926535
这是一个具有给定值(π)的通用变量 pi
,声明并不关心变量的确切类型。诚然,在实际代码中很难找到这样的东西:抽象实际上总是使用封装。但是,以上内容确实在C ++(14)中通过变量模板存在(=变量的通用模板);语法稍微复杂一些,例如:
template <typename T> constexpr T pi = T{3.1415926535};
许多答案及其示例令人误解。
封装就是数据的打包和对该数据进行操作的功能到单个组件中,并限制对某些对象组件的访问。
封装意味着对象的内部表示通常在对象定义之外的视图中不可见。
抽象是一种表示基本特征而又不包括实现细节的机制。
封装: - 信息隐藏。
抽象: - 实现隐藏。
例:
class foo{
private:
int a, b;
public:
foo(int x=0, int y=0): a(x), b(y) {}
int add(){
return a+b;
}
}
foo
类的任何对象的内部表示形式都隐藏在类外部。->封装。
对象的任何可访问成员(数据/功能)foo
均受限制,并且只能由该对象访问。
foo foo_obj(3, 4);
int sum = foo_obj.add();
方法的实现add
是隐藏的。->抽象。
qsort
在C中使用函数是抽象的示例。您不知道其实现的详细信息。这里不涉及封装。使用构造函数初始化C ++中对象的数据字段是封装的一个示例(通过构造函数控制对对象组件的访问)。
封装将一些东西放在盒子里,给你一个窥视孔;这可以防止您弄脏齿轮。
完全抽象化忽略了无关紧要的细节,例如物体是否具有齿轮,棘轮,飞轮或核芯。他们只是“走”
封装示例:
抽象的例子:
抽象是广义术语。即封装是抽象的子集。
例2:
该解决方案架构师是谁创造了高层次的人抽象的整个解决方案的技术设计,然后这个设计被移交给了开发团队的执行。
在这里,解决方案架构师充当抽象,而开发团队充当封装。
示例3:用户数据的封装(网络)
抽象(或模块化)–类型使程序员可以在比位或字节更高的层次上进行思考,而不必为低级的实现所困扰。例如,程序员可以开始将字符串视为一组字符值,而不仅仅是字节数组。更重要的是,类型使程序员能够考虑并表达两个任意大小的子系统之间的接口。这样可以实现更高级别的本地化,以便当这两个子系统进行通信时,子系统互操作性所需的定义保持一致。 资源
上面提供了很多很好的答案,但是我将在这里介绍我的(Java)观点。
数据封装只是意味着包装和控制对一个类中的逻辑分组数据的访问。它通常与另一个关键字“ 数据隐藏”关联。这是使用访问修饰符在Java中实现的。
一个简单的例子是定义一个私有变量,并使用getter和setter方法授予对它的访问权,或者使方法成为私有方法,因为它仅与类一起使用。用户无需了解这些方法和变量。
注意:封装完全是关于数据隐藏的,这一点不要误解。当我们说封装时,重点应该放在将相关数据和行为分组或打包或捆绑在一起。
另一方面,数据抽象是泛化的概念,因此底层的复杂逻辑不会暴露给用户。在Java中,这是通过使用接口和抽象类来实现的。
范例-
可以说我们有一个Animal接口,它具有一个makeSound()函数。有两个实现此接口的具体类Dog和Cat。这些具体的类具有makeSound()函数的单独实现。现在假设我们有一只动物(我们是从某个外部模块获得的)。所有用户都知道它所接收的对象是一些动物,而打印动物声音是用户的责任。一种蛮力方式是检查接收到的对象以识别其类型,然后将其类型转换为该Animal类型,然后在其上调用 makeSound()。但是更巧妙的方法是引用多态事物抽象出来。使用动物作为然后调用makeSound()。在运行时 根据实际对象类型是什么,将调用适当的函数。
更多细节在这里。
复杂的逻辑位于封装在触摸板上的电路板上,并提供了一个不错的界面(按钮)以将其抽象出给用户。
PS:以上链接是我的个人博客。
就像您开车时一样,您知道油门踏板的作用,但由于其被封装,您可能不知道其背后的过程。
让我以C#为例。假设您有一个整数:
int Number = 5;
string aStrNumber = Number.ToString();
您可以使用Number.ToString()之类的方法,该方法返回数字5的字符表示形式并将其存储在字符串对象中。该方法告诉您它是做什么的,而不是如何做到的。
这些概念有些模糊,并非计算机科学和编程所独有。我想提出一些其他想法,以帮助其他人理解这些重要概念。
封装 -隐藏和/或限制对系统某些部分的访问,同时公开必要的接口。
抽象化 -除了具体的现实,特定的对象或实际的实例以外,还考虑了某些特征被删除的事物,从而降低了复杂性。
主要相似之处在于这些技术旨在提高理解力和实用性。
主要区别在于抽象是一种更简单地表示事物的方法(通常是使表示更广泛地适用),而封装是一种更改其他事物与事物交互的方式的方法。
这是一个封装示例,希望可以使事情变得更清楚:
这里我们有一个Arduino Uno和一个位于外壳内的Arduino Uno。外壳很好地说明了封装的意义。
封装旨在保护某些组件免受外界影响和知识,并暴露其他事物应该与之交互的组件。用编程术语来说,这涉及通过访问修饰符隐藏信息,这些修饰符改变了某些变量和/或属性可以读写的程度。
但是除此之外,封装还旨在更有效地提供那些外部接口。在我们的Arduino示例中,其中可能包括漂亮的按钮和屏幕,从而使用户与设备的交互更加简单。它们为用户提供了简单的方法来影响设备的行为并获得有关其操作的有用信息,否则这些信息将更加困难。
在编程中,这涉及到各种部件的分组到一个可分离构建体,例如function
,class
,或object
。它还包括提供与这些构造进行交互的方式,以及获取有关构造的有用信息的方法。
封装以许多其他方式帮助程序员,其中不仅包括改进的代码可维护性和可测试性。
尽管这里有许多其他答案将抽象定义为概括,但我个人认为该定义是错误的。我要说的是,泛化实际上是一种特定的抽象类型,而不是相反。换句话说,所有的概括都是抽象的,但并非所有的抽象一定是概括。
这是我喜欢抽象的方式:
您会说图像中有一棵树吗?您可能会。但这真的是一棵树吗?好吧,当然不会!它是一堆像素,看起来像我们可以称之为树的东西。我们可以说它代表了真实树的抽象。注意,省略了树的一些视觉细节。而且,它不会生长,不会消耗水或产生氧气。怎么可能 它只是屏幕上的一堆颜色,由计算机内存中的字节表示。
这是抽象的本质。这是一种简化事情的方式,使它们更易于理解。贯穿您的每个想法都是现实的抽象。您对树的心理印象不再像此jpeg那样是实际的树。
在编程中,我们可以通过创建一个Tree
类来模拟生长,耗水和产生氧气的方法来利用我们的优势。我们的创作将代表我们对实际树木的体验,并且只包含我们为特定模拟真正关心的那些元素。我们使用抽象来表示我们对字节和数学的体验。
编程中的抽象还使我们能够考虑几种“具体”对象类型(实际存在的类型)之间的共性,并在唯一实体中定义这些共性。例如,我们的Tree
类可能继承自abstract class Plant
,后者具有一些适用于我们所有类植物类的属性和方法,但会删除每种植物类型特有的属性和方法。这可以大大减少代码重复,并提高可维护性。
an abstract class
和Plain 的实际区别class
在于,从概念上讲,没有“真正的”实例abstract class
。构造Plant
对象没有任何意义,因为不够具体。每个“真实” Plant
也是的一种更具体的类型Plant
。
另外,如果我们希望程序更加逼真,则可能需要考虑这样一个事实,即我们的Tree
类本身可能过于抽象。在现实中,每Tree
一个更具体的类型的Tree
,所以我们可以为那些类型,如创建类Birch
,Maple
等它继承了我们,也许现在abstract
,Tree
阶级。
另一个很好的抽象示例是Java虚拟机(JVM),它为Java代码提供了运行的虚拟或抽象计算机。它本质上消除了系统的所有平台特定组件,并提供了“计算机”的抽象接口,而无需特别考虑任何系统。
封装与抽象的不同之处在于,封装与事物的“真实”或“准确”无关。它不会删除某些组件以使其更简单或更广泛地适用。相反,它可以隐藏某些组件以实现类似的目的。
封装:正在向对象的实际用户隐藏不需要的/意外的/适当的实现细节。例如
List<string> list = new List<string>();
list.Sort(); /* Here, which sorting algorithm is used and hows its
implemented is not useful to the user who wants to perform sort, that's
why its hidden from the user of list. */
抽象:是提供概括性的一种方法,因此是处理种类繁多的对象的通用方法。例如
class Aeroplane : IFlyable, IFuelable, IMachine
{ // Aeroplane's Design says:
// Aeroplane is a flying object
// Aeroplane can be fueled
// Aeroplane is a Machine
}
// But the code related to Pilot, or Driver of Aeroplane is not bothered
// about Machine or Fuel. Hence,
// pilot code:
IFlyable flyingObj = new Aeroplane();
flyingObj.Fly();
// fighter Pilot related code
IFlyable flyingObj2 = new FighterAeroplane();
flyingObj2.Fly();
// UFO related code
IFlyable ufoObj = new UFO();
ufoObj.Fly();
// **All the 3 Above codes are genaralized using IFlyable,
// Interface Abstraction**
// Fly related code knows how to fly, irrespective of the type of
// flying object they are.
// Similarly, Fuel related code:
// Fueling an Aeroplane
IFuelable fuelableObj = new Aeroplane();
fuelableObj.FillFuel();
// Fueling a Car
IFuelable fuelableObj2 = new Car(); // class Car : IFuelable { }
fuelableObj2.FillFuel();
// ** Fueling code does not need know what kind of vehicle it is, so far
// as it can Fill Fuel**
抽象:以简化/不同的方式呈现事物的想法,它更易于理解和使用,或者与情况更相关。
考虑一个发送电子邮件的类……它使用抽象将自己展示为某种使者男孩,因此您可以调用emailSender.send(mail,收件人)。它的实际作用-选择POP3 / SMTP,呼叫服务器,MIME转换等。您只会看到您的使者男孩。
封装形式:保护和隐藏对象专有的数据和方法的想法。它使更多事情变得独立和万无一失。
以我为例。我封装了世界其他地方的心率。因为我不希望其他任何人更改该变量,也不需要其他任何人对其进行设置才能正常运行。这对我来说至关重要,但是您不需要知道它是什么,无论如何您可能都不在乎。
环顾四周,您会发现几乎触摸到的所有东西都是抽象和封装的一个例子。例如,您的电话为您提供了一种能够将您所说的话说给别人听的抽象概念-涵盖了GSM,处理器架构,无线电频率以及您不了解或不关心的数百万种其他内容。它还封装了您的某些数据,例如序列号,ID号,频率等。
这一切使世界成为生活在:D的美好之地
抽象:仅显示必要的信息。让我们集中讨论打开计算机的示例。用户不必知道系统仍在加载时发生了什么(该信息对用户是隐藏的)。
让我们再举一个例子,即ATM。客户不需要知道机器如何读取PIN并处理交易,他所需要做的就是输入PIN,提取现金并离开。
封装:用于隐藏分类的敏感数据,因此将其中的一部分私有化。这是通过不允许外部访问来使某些信息对客户保密的方法。
另一个例子:
假设我创建了一个不可变的Rectangle类,如下所示:
class Rectangle {
public:
Rectangle(int width, int height) : width_(width), height_(height) {}
int width() const { return width_; }
int height() const { return height_; }
private:
int width_;
int height_;
}
现在很明显,我已经封装了宽度和高度(访问受到了某种限制),但是我还没有抽象任何东西(好的,也许我已经忽略了矩形在坐标空间中的位置,但这是一个缺陷)。例)。
好的抽象通常意味着好的封装。
良好的抽象示例是通用数据库连接类。它的公共接口与数据库无关,并且非常简单,但是允许我通过连接执行所需的操作。你看到了吗?那里也有封装,因为类必须在内部具有所有低级句柄和调用。
Abstraction
并Encapsulation
使用一个通用的例子-------------------------------------------------- -------------------------------------------------- --------------------------------
我们都使用计算器来计算复杂的问题!
Your both example tell about just encapsulation, not abstraction
;原因抽象无关具有hiding
相当Generalizing
一种防止特定对象的数据安全地被外部功能有意或无意地滥用的机制称为“ 数据封装”
在不包括背景细节或解释的情况下表示基本特征的行为称为抽象
抽象:抽象是指显示What
部分功能。
封装:封装是指隐藏How
功能的一部分。
让我们举一个非常简单的例子
/// <summary>
/// We have an Employee class having two properties EmployeeName and EmployeeCode
/// </summary>
public class Employee
{
public string EmplpyeeName { get; set; }
public string EmployeeCode { get; set; }
// Add new employee to DB is the main functionality, so are making it public so that we can expose it to external environment
// This is ABSTRACTION
public void AddEmployee(Employee obj)
{
// "Creation of DB connection" and "To check if employee exists" are internal details which we have hide from external environment
// You can see that these methods are private, external environment just need "What" part only
CreateDBConnection();
CheckIfEmployeeExists();
}
// ENCAPLUSATION using private keyword
private bool CheckIfEmployeeExists()
{
// Here we can validate if the employee already exists
return true;
}
// ENCAPLUSATION using private keyword
private void CreateDBConnection()
{
// Create DB connection code
}
}
控制台应用程序的程序类
class Program
{
static void Main(string[] args)
{
Employee obj = new Employee();
obj.EmplpyeeName = "001";
obj.EmployeeCode = "Raj";
// We have exposed only what part of the functionality
obj.AddEmployee(obj);
}
}
封装将复杂性封装在一个类(因此是封装)中,因此……抽象是对象的特征,与其他对象有所不同...
可以通过使具有一个或多个方法的类抽象化来实现抽象。这不过是扩展类应该实现的特性。例如,当您发明/设计汽车时,您要定义一个特征,例如汽车应具有4个门,门,方向盘等…,因此任何使用此设计的人都应包括该特征。实现不是抽象的头。它将仅定义应包括的特征。
通过使用访问修饰符(如public,private,protected以及继承,聚合或组合),可以将数据和行为保存在class&的一个封装中,从而实现封装。因此,您也只显示所需的内容,只显示想要显示的范围。例如,公共的,受保护的,友好的和私人的ka基础……例如,通用汽车决定使用上面抽象的汽车设计。但是他们拥有具有相同特性和几乎相同功能的各种产品。因此,他们编写了扩展上述抽象类的类。它说齿轮箱应该如何工作,刹车应该如何工作,方向盘应该如何工作。然后所有产品都使用此通用功能。他们不需要知道齿轮箱是如何工作的,折断的工作原理或转向器的工作原理。
两者都很强大;但是使用抽象比封装需要更多的技能,并且更大的应用程序/产品在没有抽象的情况下无法生存。
从这个
OOPS中封装与抽象之间的区别
抽象和封装是两个重要的面向对象编程(OOPS)概念。封装和抽象都是相互关联的术语。
封装与抽象之间的现实差异
封装意味着隐藏。封装也称为数据隐藏。您可以认为封装就像将药物隐藏在其中的胶囊(药片)一样。封装是包装,只是隐藏属性和方法。封装用于将代码和数据隐藏在一个单元中,以保护数据免受外界干扰。类是封装的最佳示例。
抽象是指仅向目标用户显示必要的细节。顾名思义,抽象是“任何事物的抽象形式”。我们在编程语言中使用抽象来制作抽象类。抽象类表示类的方法和属性的抽象视图。
封装和抽象之间的实现差异
使用接口和抽象类实现抽象,而使用私有和受保护的访问修饰符实现封装。
OOPS通过防止程序员以非预期的方式访问数据来利用封装来增强类型的完整性(即,确保以适当的方式使用数据)。通过封装,只有预定的一组功能可以访问数据。与访问限制(公共/私有等)捆绑在一起的数据类型和操作(方法)的总称是一类。
我将尝试以一种简单的方式来演示封装。
封装是-
封装实现抽象。
而且抽象是-
让我们看一个例子-
下图显示了“要添加到数据库中的客户详细信息”的GUI。
通过查看图像,我们可以说我们需要一个客户类别。
步骤-1:我的客户类别需要什么?
即
1将客户代码和客户名称添加到数据库的功能。
名称空间CustomerContent {公共类Customer {公共字符串CustomerCode =“”; 公用字符串CustomerName =“”; public void ADD(){//我的数据库代码会在这里}
现在,只有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();
}
}
现在无需向最终用户显示Extra方法(Validate(); CreateDBObject()[复杂方法和Extra方法])。最终用户只需查看并了解客户代码,客户名称和添加按钮即可添加最终用户不在乎它将如何将数据添加到数据库?。
步骤-3:私有不涉及最终用户交互的其他复杂方法。
因此,将那些复杂的Extra方法设为Private而不是Public(即,隐藏这些方法)并删除obj.Validate();。obj.CreateDBObject(); 从主类Program中,我们实现了封装。
换句话说,简化与最终用户的接口就是封装。
所以现在代码如下所示-
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-上面的代码很难实现。
对于抽象或封装,信息隐藏不是严格要求的。信息可能会被忽略,但不必隐藏。
封装 是将某事物视为一件事物的能力,即使它可能由许多复杂的部分或构想组成。例如,我可以说我坐在“椅子”上,而不是指椅子的许多不同部分,每个部分都有特定的设计和功能,所有这些部分都精确地装配在一起,目的是舒适地握住我的臀部几英尺远离地板。
通过封装启用抽象。因为我们封装了对象,所以我们可以将它们视为以某种方式彼此关联的事物,而不必陷入内部对象结构的微妙细节中。抽象是考虑更大的图景的能力,而不必担心小细节。这个词的根是抽象的,就像出现在学术论文顶部的摘要中一样,而不是抽象的类,而只能是作为派生子类实例化的类。
老实说,当我把屁股放到椅子上时,我从没想过椅子的结构如何抓住并保持体重。这是一个足够体面的椅子,我不必担心这些细节。因此,我可以将注意力转向计算机。再说一次,我不考虑计算机的组成部分。我只是在看网页的一部分,该部分代表我可以输入的文本区域,而且我正在用文字进行交流,甚至根本没有想到我的手指如何总是如此迅速地在键盘上找到正确的字母,以及如何最终在点击这些键和发布到该论坛之间建立了联系。这是抽象的强大力量。由于可以信任较低级别的系统,因此可以一致且精确地工作,因此,我们会留意进行更多工作。
class Aeroplane : IFlyable, IFuelable, IMachine
{ // Aeroplane's Design says:
// Aeroplane is a flying object
// Aeroplane can be fueled
// Aeroplane is a Machine
}
// But the code related to Pilot, or Driver of Aeroplane is not bothered
// about Machine or Fuel. Hence,
// pilot code:
IFlyable flyingObj = new Aeroplane();
flyingObj.Fly();
// fighter Pilot related code
IFlyable flyingObj2 = new FighterAeroplane();
flyingObj2.Fly();
// UFO related code
IFlyable ufoObj = new UFO();
ufoObj.Fly();
// **All the 3 Above codes are genaralized using IFlyable,
// Interface Abstraction**
// Fly related code knows how to fly, irrespective of the type of
// flying object they are.
// Similarly, Fuel related code:
// Fueling an Aeroplane
IFuelable fuelableObj = new Aeroplane();
fuelableObj.FillFuel();
// Fueling a Car
IFuelable fuelableObj2 = new Car(); // class Car : IFuelable { }
fuelableObj2.FillFuel();
// ** Fueling code does not need know what kind of vehicle it is, so far
// as it can Fill Fuel**
抽象是对用户隐藏无用的数据,封装是将数据绑定到一个胶囊(一个类)中。我认为封装是我们实现抽象的方式。
Abstraction
是我们要做的实施合同。实施可能会随着时间的流逝而改变。各种实现本身可能会隐藏,也可能不会隐藏,但会被屏蔽在抽象后面。
假设我们定义所有的APIs
一类在interface
那么请问我们的代码在用户的定义为depened APIs
的interface
。仅在必须遵守既定合同的情况下,我们才能自由地改进或修改实施。用户未耦合与我们的实施结合。
我们以抽象方式公开所有必要规则(方法),这些规则的实现留给实现者实体,而实现也不属于抽象的一部分。它只是签名和声明,是什么构成了抽象。
Encapsulation
只是通过减少状态和行为的访问来隐藏内部细节。封装的类可能没有定义好Abstraction
。
java.util.List
是的抽象java.util.ArrayList
。java.util.ArrayList
用non public
访问修饰符标记的内部状态是封装。
编辑
假设一类Container.nava implements IContainer
,IContainer
可以声明的方法,如addElement
,removeElements
,contains
,等在这里IContainer
代表了它的实现类的抽象。抽象是将类,模块或系统的API声明给外部世界。这些API成为contract
。该系统可能尚未开发。系统的用户现在可以依赖于声明的API,并确保任何实施此类合同的系统将始终遵守声明的API,他们将始终为这些API提供实现。一旦我们写了一个具体的实体,然后决定隐藏我们的内部状态就是封装
简而言之
抽象使用->封装 和 封装使用->数据隐藏
要么
数据隐藏是封装的一个子集,并 封装是抽象的一个子集