Simple way to understand Encapsulation and Abstraction
学习OOP概念特别有兴趣了解抽象和封装在深度。
下面检查
抽象vs信息隐藏vs封装
抽象与封装的区别
我发现很难理解这些概念的真实性和简单的例子
One of my colleagues said abstraction is nothing but creating abstract
class and normal class that protects its member variable with scope is
called Encapsulation.
难道有一个简单的方式我能理解和帮助其他人了解他们的真实身份,而不是重复他们的下面吗?Do there a simple way I can understand and help others to understand what they are exactly,rather than repeating the below?
BLCK1/
抽象是一个只显示"相关"数据并"隐藏"不必要的对象细节的过程。考虑到你的手机,你只需要知道在发送信息或打电话时要按下什么按钮,当你按下按钮时会发生什么,你的信息是如何发送的,你的电话是如何连接的,这些都是从用户那里抽象出来的。
封装是将数据和函数组合成一个称为类的单个单元的过程。在封装中,数据不是直接访问的;而是通过类中存在的函数访问的。简单来说,类的属性是私有的,并提供公共getter和setter方法来操纵这些属性。因此,封装使得数据隐藏的概念成为可能。
抽象是隐藏信息或只向客户提供必要的细节。
例如汽车刹车——你只知道踩下踏板会让汽车停下来,但你不需要知道它内部是如何工作的。
明天抽象的优势如果制动器实现从鼓式制动器更改为盘式制动器,作为客户,您不需要更改(即您的代码不会更改)
封装是将数据和行为绑定到一个单元中。它也是一种语言机制,用于限制对某些组件的访问(这可以通过访问修饰符实现,如private、protected等)。
例如,类具有属性(即数据)和行为(即操作该数据的方法)
使用C的示例#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | //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的"功能"。拥有一组消防队员(名单),这意味着穴居人和有火柴的人都是有效的选择。
这意味着
1 2 3 4 5 6 | //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等),所以这些步骤是隐藏在视图中的,因为它们是类的内部关注点。穴居人还有许多其他的公众行为,可以被外界称为。但有些细节总是隐藏的,因为与内部工作有关。它们是私有的,只存在于对象中,从不暴露。这是封装
Abstraction is generalised term. i.e. Encapsulation is subset of Abstraction.
抽象是管理复杂系统的强大方法。抽象由定义良好的对象及其层次分类管理。
例如,汽车本身就是一个定义明确的对象,它由其他几个较小的对象组成,如传动系统、转向机构、发动机,这些对象又有自己的子系统。但是对于人类来说,汽车是一个单一的对象,它可以通过它的子系统来管理,即使它们的内部细节是未知的。礼貌
封装:将数据成员和方法封装到一个单元(即类)中称为封装。
封装就像是封闭在胶囊中。它将与对象相关的操作和数据封闭到该对象中。
封装就像你的包,你可以把笔、书等放在里面,这意味着这是封装成员和函数的特性。
1 2 3 4 5 | class Bag{ book; pen; ReadBook(); } |
封装意味着隐藏一个对象的内部细节,即一个对象是如何做事情的。
封装防止客户机看到其内部视图,在那里实现抽象行为。
封装是一种用于保护对象中的信息与另一对象的信息的技术。
隐藏数据的安全性,例如将变量设为私有,并公开属性以访问将公开的私有数据。
因此,当您访问该属性时,可以验证数据并将其设置。礼貌
我将用一个真实的例子来解释抽象。假设你家里有一个电源插头,许多设备可以连接到同一个插头,但是插头永远不会知道它连接到哪个设备,换句话说,设备的细节被抽象(隐藏)到插头上。
想一想,如果我们把一个设备直接连到电线上而不带插头怎么办?假设将一个灯泡直接连接到一根电线上,那么电线就知道它连接到哪一个设备,当我们需要更换灯泡时,我们就必须从灯泡上拆下电线连接,这意味着灯泡与电线紧密耦合。换句话说,灯泡和电线知道它连接的细节,意味着不抽象。
在面向对象的世界中,抽象的工作原理完全相同。使用其他类函数/属性的类不需要知道它使用的是哪个类函数/属性,所有内容都应该用接口/抽象类进行抽象。
让我编写相同的示例。这里我有一个班级"电气插头",这是运行一个设备。但是"电气插头"一类并不知道它在运行哪个设备。它可以是实现接口"idevice"的任何类,这意味着"rundevice"的实现是从"electricalplug"中抽象出来的。这是完整的示例代码,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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"); } } |
抽象是一个过程,在这个过程中,您从计划在设计中捕获/表示的实体中"丢弃"不必要的细节,并且只保留与您的域相关的实体的属性。例如:为了表示汽车,你可以保留例如车型和价格、当前位置和当前速度,忽略颜色和座位数量等。
封装是属性的"绑定"以及在单个抽象单元(即类)中操作它们的操作。因此,该车将配备控制位置和当前速度等的
封装是一种将一个盒子放在某物周围以保护其内容的方法。抽象是提取某个东西的功能属性,这样您就可以只使用提取的内容来执行操作,而不需要了解内部工作。
当我们说两种物质是液体时,我们用"液体"来抽象我们选择讨论的那些物质的性质。这种抽象告诉我们,根据我们以前对液体的经验,我们可以对物质做些什么。
抽象也与继承人无关。你可以有另一种抽象,比如"金属",它以不同的方式提取物质的属性。
抽象忽略了细节,所以如果你使用的是一个特定的抽象,你就不应该询问抽象不允许的底层物质的属性。就像你把牛奶和水混合在一起,你很难再问你有多少牛奶。
函数是对具有某种映射概念的事物的抽象,也就是说,您可以对其内部内容运行函数,将内部位转换为其他任何内容。外部的东西是一样的。
其中有用的是,如果您有一个在列表上工作的函数,并且您意识到您只依赖于映射接口,那么您可以依赖于该函数,然后您的函数可以与流、承诺、可能是、元组以及其他共享该抽象的东西一起工作。
像haskell这样的函数语言有一些非常强大的抽象能力,使得极端的代码重用成为现实。
抽象是为了简化接口而隐藏细节的一种方法。
因此,以汽车为例,汽车中的所有控件都是抽象的。这允许您在不了解转向、加速或减速系统基本细节的情况下操作车辆。
一个好的抽象是在一个类似问题的多个实例中广泛地标准化一个接口。一个伟大的抽象可以改变一个行业。
现代方向盘、制动踏板和油门踏板都是伟大抽象的例子。汽车转向最初看起来更像自行车转向。刹车和节流阀都是用手操作的。但我们今天使用的抽象是如此强大,它们席卷了整个行业。
——
封装是一种隐藏细节的方法,以防止外部操作。
封装可以防止驾驶员操纵汽车的驾驶方式——从转向、悬架和制动的刚度到节气门和变速箱的特性。大多数汽车不提供改变这些东西的接口。这种封装可确保车辆按照制造商的预期运行。
一些汽车提供了少量的驾驶模式,如豪华、运动和经济,这允许驾驶员同时改变这些属性。通过提供驾驶模式,制造商允许驾驶员对经验进行一些控制,同时防止他们选择将使车辆变得不愉快或不安全的属性组合。这样,制造商就隐藏了细节,以防止不安全的操作。这是封装。
抽象就像使用计算机一样。
除了GUI(图形用户界面)和外部硬件(例如屏幕)之外,你完全不知道发生了什么。所有这些漂亮的颜色等等。作为一般消费者,您只会看到与您相关的详细信息。
封装是隐藏不相关细节的实际行为。
你使用你的电脑,但是你看不到它的CPU(中央处理器)是什么样子的(除非你试图闯入它)。它隐藏(或封装)在所有的铬和塑料后面。
在面向对象编程(OOP)语言的上下文中,通常会有这种设置:
1 2 3 4 5 | CLASS { METHOD { *the actual code* } } |
"封装"的一个例子是有一个普通用户看不见的方法(私有)。抽象"是指常规用户使用他们可以(公开)的方法来使用私有方法。
封装可以被认为是一种包装纸,用于将数据和功能捆绑在一起,作为一个单独的单元,它可以保护数据免受各种外部污垢的影响(我的意思是外部功能)。
抽象包括缺少细节和使用简单的接口来控制复杂的系统。
例如,我们可以通过按下按钮来点亮灯泡,而不必担心底层的电气工程(抽象)。
但是,你不能用任何其他方式点亮灯泡。(封装)
数据提取:访问任何类的数据成员和成员函数简单地称为数据抽象。
封装:绑定变量和函数或1可以说数据成员或成员函数在一个单元中一起被称为数据封装…
抽象是向用户显示必要的信息,在这种情况下,封装会向用户隐藏不需要的数据(产品对用户)。
封装实现了抽象。
抽象是封装实际实现它的过程。例如,添加用户逻辑->我们需要验证用户,创建数据库连接并插入用户。所以用户不知道首先需要调用validate函数,创建db连接,然后在db中插入值。他只调用adduser函数,该函数使用in调用内部所有逻辑,这只是封装(对特性分组并隐藏方法)。
数据抽象:DA只是对具体项目进行过滤。通过类,我们可以实现纯抽象,因为在创建类之前,我们只能考虑有关类的信息。
封装:它是一种机制,通过它保护我们的数据不受外界影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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(); } } } } |