Java 中的抽象与封装

2022-08-31 11:30:10

可能的副本:
抽象 VS 信息隐藏 VS 封装

我知道这个问题可能已经在这个论坛上被问了数千次,甚至网络也充满了关于这些概念的许多定义,但听起来都一样,都使用相同的技术词。例如,以下定义

封装是将数据和对数据进行操作的代码绑定或包装到单个实体中的过程。这可以保护数据免受外部接口和误用的影响。考虑封装的一种方法是作为保护性包装器,防止代码和数据被包装器外部定义的其他代码任意访问。

我从上面的定义中了解到,创建变量,将它们标记为私有并为这些变量生成 getter-setter,并使用 object 来访问这些 getter 和 setter。通过这种方式,数据隐藏在对象内部,只能通过对象访问。希望我是对的


抽象是Java中用于隐藏某些细节并仅显示对象的基本功能的过程。换句话说,它处理对象(接口)的外部视图。

现在,这是总是让我感到困惑的部分。每当我想到抽象时,我想到的就是抽象类(可能是因为两者都有抽象关键字)。上面的定义说抽象意味着隐藏数据,只显示所需的细节,但这就是我们已经在封装中做的事情,对吧?那么有什么区别。另外,我没有得到什么是对象的外侧视图,它处理对象的外部视图

如果可能的话,有人可以用一些现实生活中的例子或一些程序化的例子来说明这一点吗?


答案 1

OO抽象发生在类级设计期间,目的是隐藏API /设计/系统提供的功能如何实现的实现复杂性,从某种意义上说,简化了访问底层实现的“接口”。

抽象过程可以在越来越“更高”的类(层)上重复,这使得可以在不增加每层代码和理解的复杂性的情况下构建大型系统。

例如,Java开发人员可以使用FileInputStream的高级功能,而不必担心它是如何工作的(即文件句柄,文件系统安全检查,内存分配和缓冲将在内部管理,并且对消费者隐藏)。这允许更改 的实现,并且只要 API(接口)保持一致,针对以前版本构建的代码仍然可以工作。FileInputStreamFileInputStream

同样,在设计自己的类时,您将需要尽可能地向其他人隐藏内部实现细节。

在Booch定义1中,OO封装是通过信息隐藏来实现的,特别是围绕隐藏类实例拥有的内部数据(字段/表示状态的成员),通过以受控方式强制访问内部数据,并防止对这些字段的直接外部更改,以及隐藏类的任何内部实现方法(例如,通过使它们私有)。

例如,默认情况下可以创建类的字段,并且仅当需要对这些字段进行外部访问时,才会从类中公开和/或(或)(在现代OO语言中,字段可以标记为/ /,这进一步限制了更改,即使在类内也是如此)。privateget()set()Propertyreadonlyfinalimmutable

未应用任何信息隐藏的示例(不良做法):

class Foo {
   // BAD - NOT Encapsulated - code external to the class can change this field directly
   // Class Foo has no control over the range of values which could be set.
   public int notEncapsulated;
}

应用字段封装的示例

class Bar {
   // Improvement - access restricted only to this class
   private int encapsulatedPercentageField;

   // The state of Bar (and its fields) can now be changed in a controlled manner
   public void setEncapsulatedField(int percentageValue) {
      if (percentageValue >= 0 && percentageValue <= 100) {
          encapsulatedPercentageField = percentageValue;
      }
      // else throw ... out of range
   }
}

字段的不可变/仅构造函数初始化示例

class Baz {
   private final int immutableField;

   public void Baz(int onlyValue) {
      // ... As above, can also check that onlyValue is valid
      immutableField = onlyValue;
   }
   // Further change of `immutableField` outside of the constructor is NOT permitted, even within the same class 
}

Re : 抽象 vs 抽象类

抽象类是促进类之间通用性的重用的类,但其本身不能直接实例化 - 抽象类必须被子类化,并且只有(非抽象的)子类可以被实例化。和 之间的混淆之一可能是,在OO的早期,继承更多地用于实现代码重用(例如,与相关的抽象基类)。如今,组合通常比继承更受青睐,并且有更多的工具可用于实现抽象,例如通过接口,事件/委托/函数,特征/mixins等。new()concreteAbstractionabstract class

Re : 封装 vs 信息隐藏

封装的含义似乎随着时间的推移而发展,最近,在确定将哪些方法,字段,属性,事件等捆绑到类中时,封装通常也可以在更一般的意义上使用。

引用维基百科:

在面向对象编程语言的更具体的设置中,该概念用于表示信息隐藏机制,捆绑机制或两者的组合。

例如,在语句中

我已将数据访问代码封装到它自己的类中

..封装的解释大致相当于关注点分离单一责任主体(SOLID中的“S”),并且可以作为重构的同义词。


[1] 一旦你看过Booch的封装猫图片,你将永远无法忘记封装 - 面向对象分析和设计与应用程序,第2版


答案 2

简单来说:在决定实现什么时,你做抽象。在隐藏已实现的内容时,会执行封装。