Kon*_*lph 255
这里的大多数答案都集中在OOP上,但封装开始得更早:
每个功能都是封装 ; 在伪代码中:
point x = { 1, 4 }
point y = { 23, 42 }
numeric d = distance(x, y)
Run Code Online (Sandbox Code Playgroud)
这里,distance
封装了平面中两点之间(欧几里德)距离的计算:它隐藏了实现细节.这是封装,纯粹而简单.
抽象是一个泛化的过程:采取具体的实现并使其适用于不同的,虽然有些相关的数据类型.经典的抽象示例是C的qsort
数据排序功能:
问题qsort
在于它并不关心它所分类的数据 - 事实上,它不知道它分类的数据.相反,它的输入类型是无类型指针(void*
),它只是C的说法"我不关心数据的类型"(这也称为类型擦除).重要的是qsort
,无论数据类型如何,执行始终保持不变.那唯一有改变的是比较功能,从数据类型的数据类型而有所不同.qsort
因此,期望用户提供所述比较函数作为函数参数.
封装和抽象齐头并进,以至于你可以说明它们是真正不可分割的.出于实际目的,这可能是真的; 那说,这是一个封装,不是一个抽象:
class point {
numeric x
numeric y
}
Run Code Online (Sandbox Code Playgroud)
我们封装了点的坐标,但除了在逻辑上对它们进行分组之外,我们并没有实质性地将它们抽象出来.
这里是一个抽象的例子,它不是封装:
T pi<T> = 3.1415926535
Run Code Online (Sandbox Code Playgroud)
这是一个具有给定值(π)的泛型变量 pi
,声明并不关心变量的确切类型.不可否认,我很难在实际代码中找到这样的东西:抽象几乎总是使用封装.但是,上述确实存在于C++(14)中,通过变量模板(=变量的通用模板); 使用稍微复杂的语法,例如:
template <typename T> constexpr T pi = T{3.1415926535};
Run Code Online (Sandbox Code Playgroud)
dir*_*tly 128
封装隐藏了实现细节,这些细节可能是也可能不是通用或专用行为.
抽象提供了一种概括(比如一组行为).
这是一个很好的阅读:对象机构的Edward V. Berard的抽象,封装和信息隐藏.
hac*_*cks 112
许多答案和他们的例子都是误导性的.
封装是将对该数据进行操作的数据和函数打包到单个组件中,并限制对某些对象组件的访问.
封装意味着对象的内部表示通常在对象定义之外的视图中隐藏.
抽象是一种代表基本功能而不包含实现细节的机制.
封装: - 信息隐藏.
抽象: - 实施隐藏.
例:
class foo{
private:
int a, b;
public:
foo(int x=0, int y=0): a(x), b(y) {}
int add(){
return a+b;
}
}
Run Code Online (Sandbox Code Playgroud)
foo
类的任何对象的内部表示都隐藏在类之外. - >封装.
对象的任何可访问成员(数据/函数)foo
都受到限制,并且只能由该对象访问.
foo foo_obj(3, 4);
int sum = foo_obj.add();
Run Code Online (Sandbox Code Playgroud)
方法的实现add
是隐藏的. - >抽象.
Ste*_*owe 96
封装将一些东西放在一个盒子里,然后给你一个窥视孔; 这可以防止你对齿轮进行捣乱.
抽象平局忽略了无关紧要的细节,比如是否有齿轮,棘轮,飞轮或核心; 他们只是"走"
封装的例子:
抽象的例子:
Ani*_*kur 30
上面提供了很多好的答案,但我将在这里提出我的(Java)观点.
数据封装只是意味着包装和控制类中逻辑分组数据的访问.它通常与另一个关键字 - 数据隐藏相关联.这是使用访问修饰符在Java中实现的.
一个简单的例子是定义一个私有变量,并使用getter和setter方法提供对它的访问,或者将一个方法设为私有,因为它只使用该类.用户无需了解这些方法和变量.
注意:不应该误解封装只是关于数据隐藏.当我们说封装时,重点应放在分组或打包或捆绑相关数据和行为上.
另一方面,数据抽象是概括的概念,因此下面的复杂逻辑不会暴露给用户.在Java中,这是通过使用接口和抽象类来实现的.
示例 -
假设我们有一个接口Animal,它有一个函数makeSound().有两个具体的类Dog和Cat实现了这个接口.这些具体类具有makeSound()函数的单独实现.现在让我们说我们有一只动物(我们从一些外部模块得到这个).所有用户都知道它接收的对象是动物,用户有责任打印动物声音.一种强制方式是检查收到的对象以识别它的类型,然后将其类型化为该Animal类型,然后在其上调用 makeSound().但更简洁的方法是将事物抽象出来.使用Animal作为多态参考并在其上调用makeSound().在运行时,取决于真实的Object类型是什么,将调用适当的函数.
更多细节在这里.
复杂逻辑位于电路板中,封装在触摸板中,并提供了一个漂亮的界面(按钮)以将其抽象给用户.
PS:以上链接是我个人的博客.
jas*_*nco 29
就像你开车时一样,你知道油门踏板的作用但你可能不知道它背后的过程,因为它是封装的.
让我举一个C#的例子.假设你有一个整数:
int Number = 5;
string aStrNumber = Number.ToString();
Run Code Online (Sandbox Code Playgroud)
您可以使用Number.ToString()之类的方法返回数字5的字符表示形式,并将其存储在字符串对象中.该方法告诉您它的作用而不是它是如何做的.
Nan*_*ard 25
这些有些模糊的概念并非计算机科学和编程所独有.我想提供一些额外的想法,可以帮助其他人理解这些重要的概念.
封装 - 隐藏和/或限制对系统某些部分的访问,同时暴露必要的接口.
抽象 - 除了具体的现实,特定的对象或实际的实例之外,考虑去除某些特征的东西,从而降低复杂性.
主要的相似之处在于这些技术旨在提高理解力和实用性.
主要区别在于抽象是一种更简单地表示事物的方法(通常是为了使表示更广泛适用),而封装是一种改变其他事物与某事物相互作用的方法.
这是一个封装的例子,希望能让事情变得更加清晰:
在这里,我们有一个Arduino Uno,以及一个机箱内的Arduino Uno.封装是封装的全部代表.
封装旨在保护某些组件免受外部影响和知识的影响,以及暴露其他东西应该与之交互的组件.在编程术语中,这涉及通过访问修饰符隐藏信息,这改变了可以读取和写入某些变量和/或属性的程度.
但除此之外,封装还旨在更有效地提供这些外部接口.使用我们的Arduino示例,这可能包括漂亮的按钮和屏幕,这使得用户与设备的交互更加简单.它们为用户提供了影响设备行为的简单方法,并获得有关其操作的有用信息,否则将更加困难.
在编程中,这涉及的各种组件成可分离构建体,如一个的分组function
,class
或object
.它还包括提供与这些结构交互的方法,以及获取有关它们的有用信息的方法.
封装以许多其他方式帮助程序员,尤其是改进的代码可维护性和可测试性.
虽然这里的许多其他答案都将抽象定义为概括,但我个人认为该定义是错误的.我会说泛化实际上是一种特定的抽象类型,而不是相反.换句话说,所有概括都是抽象,但所有抽象都不一定是概括.
这就是我喜欢抽象的方式:
你会说那里有一棵树吗?你有可能.但它真的是一棵树吗?好吧,当然不是!它是一堆看起来像我们可能称之为树的像素.我们可以说它是一棵真树的抽象.请注意,省略了树的几个可视细节.此外,它不会生长,消耗水或产生氧气.怎么可能呢?它只是屏幕上的一堆颜色,由计算机内存中的字节表示.
这是抽象的本质.这是一种简化事物的方式,因此更容易理解.贯穿始终的每一个想法都是对现实的抽象.你的树的心理形象不再是这个jpeg的实际树.
在编程中,我们可以通过创建一个Tree
具有模拟生长,耗水和氧气生成方法的类来利用它.我们的创作将代表我们对实际树木的体验,并且仅包括我们真正关心的特定模拟元素.我们使用抽象作为表示我们对字节和数学的经验的一种方式.
编程中的抽象还允许我们考虑几个"具体"对象类型(实际存在的类型)之间的共性,并在唯一实体中定义这些共性.例如,我们的Tree
类可以继承自一个abstract class Plant
,它有几个适用于我们所有类植物类的属性和方法,但是删除那些特定于每种植物类型的属性和方法.这可以显着减少代码重复,并提高可维护性.
a abstract class
和plain 的实际区别class
在于概念上没有"真实"的实例abstract class
.构造一个Plant
对象是没有意义的,因为那不够具体.每个"真实" Plant
也是一种更具体的类型Plant
.
此外,如果我们希望我们的程序更加真实,我们可能要考虑这样一个事实,即我们的Tree
类本身可能过于抽象.在现实中,每Tree
一个更具体的类型的Tree
,所以我们可以为那些类型,如创建类Birch
,Maple
等等.从我们的继承,也许现在abstract
,Tree
阶级.
抽象的另一个好例子是Java虚拟机(JVM),它为运行的Java代码提供虚拟或抽象计算机.它基本上剥夺了系统的所有平台特定组件,并提供了"计算机"的抽象接口,而不考虑任何系统.
封装与抽象的不同之处在于它与"真实"或"准确"某些东西没有任何关系.它不会删除某些内容的组件,以使其更简单或更广泛适用.相反,它可能隐藏某些组件以实现类似的目的.
Nil*_*han 22
封装:从对象的实际用户隐藏不需要/不期望/正当的实现细节.例如
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. */
Run Code Online (Sandbox Code Playgroud)
抽象:是一种提供泛化的方式,因此是一种与广泛多样化的对象一起工作的常用方法.例如
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**
Run Code Online (Sandbox Code Playgroud)
Sud*_*han 12
抽象:以简化/不同的方式呈现内容的想法,这种方式更容易理解和使用,或者与情况更相关.
考虑一个发送电子邮件的类......它使用抽象向你展示自己作为某种信使的男孩,所以你可以调用emailSender.send(邮件,收件人).它实际上做了什么 - 选择POP3/SMTP,调用服务器,MIME翻译等,被抽象掉了.你只看到你的使者男孩.
封装:保护和隐藏对象私有的数据和方法的想法.它更多地涉及使某些东西独立和万无一失.
以我为例.我把自己的心率从世界其他地方封装起来.因为我不希望任何其他人改变该变量,我不需要任何其他人来设置它以便我运行.它对我来说至关重要,但你不需要知道它是什么,你可能也不在乎.
环顾四周,你会发现你触摸的几乎所有内容都是抽象和封装的一个例子.例如,您的手机向您展示了能够接受您所说的话并向其他人说出的抽象 - 覆盖GSM,处理器架构,无线电频率以及您不理解或不关心的其他一百万件事.它还封装了您的某些数据,如序列号,ID号,频率等.
这一切都让世界变得更加美好:D
小智 10
抽象:仅显示必要的信息.让我们关注打开计算机的例子.用户不必知道系统仍在加载时发生了什么(该信息对用户是隐藏的).
让我们再看一下ATM的例子.客户不需要知道机器如何读取PIN并处理交易,他只需输入PIN,拿走现金并离开.
封装:处理隐藏clas的敏感数据,从而私有化其中的一部分.这是一种通过不允许从外部访问它来将某些信息保密给其客户的方法.
另一个例子:
假设我创建了一个不可变的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_;
}
Run Code Online (Sandbox Code Playgroud)
现在很明显我已经封装了宽度和高度(访问在某种程度上受到限制),但我没有抽象出任何东西(好吧,也许我已经忽略了矩形在坐标空间中的位置,但这是一个缺陷例).
良好的抽象通常意味着良好的封装.
良好抽象的一个例子是通用数据库连接类.它的公共接口是数据库无关的,非常简单,但允许我通过连接做我想做的事情.而你看到了吗?那里还有封装,因为类必须具有所有低级句柄和内部调用.
Abstraction
并Encapsulation
使用一个通用的例子-------------------------------------------------- -------------------------------------------------- --------------------------------
我们都使用计算器来计算复杂的问题!
抽象:抽象意味着显示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
}
}
Run Code Online (Sandbox Code Playgroud)
控制台应用程序的程序类
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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
我们来看一个堆栈的例子.它可以使用数组或链表实现.但它支持的操作是推送和弹出.
现在抽象只暴露了push和pop接口.底层表示是隐藏的(它是一个数组还是一个链表?),并提供了一个定义良好的接口.现在,您如何确保不会对抽象数据进行意外访问?这就是封装的用武之地.例如,C++中的类使用访问说明符来确保防止意外访问和修改.而且,通过将上述接口公之于众,它确保了操纵堆栈的唯一方法是通过定义良好的接口.在这个过程中,它已经耦合了数据和可以操作它的代码(让我们不在这里涉及友元函数).也就是说,代码和数据被绑定在一起或绑定或封装.
我读得越多,就越感到困惑。所以,这就是我的理解:
封装:
我们通常从外面看到一块手表,它的部件都封装在手表的内部。我们对不同的操作有某种控制。这种隐藏细节和暴露控制(例如设置时间)的方式就是封装。
抽象:
到目前为止我们正在谈论手表。但我们没有具体说明是哪种手表。它可以是数字的或模拟的,用于手持或墙壁。有很多可能性。我们所知道的是,它是一块手表,它可以显示时间,而时间是我们唯一感兴趣的东西。这种隐藏细节并暴露通用功能或用例的方式就是抽象。
封装正在将复杂性包含在一个类中并因此封装......而抽象是一个与其他对象不同的对象的特征......
抽象可以通过使具有一个或多个方法抽象的类抽象来实现.这只不过是扩展它的类应该实现的特性.例如,当您发明/设计汽车时,您定义的特征如汽车应该有4个门,断裂,方向盘等......所以任何使用此设计的人都应该包含这些特性.实现不是每个抽象的头.它只会定义应包含的特征.
实现封装是通过利用访问修饰符(如公共,私有,受保护以及继承,聚合或组合)将数据和行为保持在一个类别的封装中.因此,您只展示所需的东西,也只展示您想要展示的范围.即公共,受保护,友好和私人的基础......例如,GM决定使用上述汽车的抽象设计.但是它们具有各种具有相同特性并且具有几乎相同功能的产品.所以他们写了一个扩展上面抽象类的类.它说明了齿轮箱应该如何工作,应该如何工作,方向盘应该如何工作.然后所有产品都使用这种通用功能.他们不需要知道齿轮箱是如何工作的,也不知道工程或转向风的工作原理.Indivisual产品肯定有更多功能,如a/c或自动锁等......
两者都很强大; 但是使用抽象需要比封装更多的技能,更大的应用程序/产品无法在不抽象的情况下生存.
小智 5
我将尝试以简单的方式演示封装..让我们看看..
封装是 -
封装实现抽象。
而抽象是——
让我们看一个例子——
下图显示了“要添加到数据库中的客户详细信息”的 GUI。
通过查看图像,我们可以说我们需要一个客户类。
步骤 - 1:我的客户类别需要什么?
IE
1 将客户代码和客户名称添加到数据库中的函数。
命名空间 CustomerContent { public class Customer { public string 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();
}
}
Run Code Online (Sandbox Code Playgroud)
现在不需要向最终用户显示额外的方法(Validate(); CreateDBObject() [复杂和额外的方法])。最终用户只需要查看和了解客户代码、客户名称和添加按钮记录.. 最终用户不关心它将如何将数据添加到数据库?。
步骤-3:私有不涉及最终用户交互的额外和复杂的方法。
因此,将那些复杂和额外的方法设为私有而不是公有(即隐藏这些方法)并删除 obj.Validate(); obj.CreateDBObject(); 从类 Program 中的 main 开始,我们实现了封装。
换句话说,简化最终用户的接口就是封装。
所以现在代码如下所示 -
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();
}
}
Run Code Online (Sandbox Code Playgroud)
概括 :
步骤 -1:我的客户类需要什么?是抽象。
第-3 步:第-3 步:私有不涉及最终用户交互的额外和复杂的方法是封装。
PS - 上面的代码很难而且很快。
归档时间: |
|
查看次数: |
382605 次 |
最近记录: |