我一直在阅读这本书Clean Code: A Handbook of Agile Software Craftsmanship,在第六章第95-98页中,它阐明了对象与数据结构之间的差异:
对象隐藏抽象背后的数据,并公开对该数据进行操作的函数。数据结构暴露了他们的数据,没有任何有意义的功能。
对象公开行为并隐藏数据。这使得在不改变现有行为的情况下添加新类型的对象变得容易。它还使得很难向现有对象添加新行为。
数据结构公开数据并且没有重要行为。这使得向现有数据结构添加新行为变得容易,但却难以向现有函数添加新数据结构。
对于某些类是对象还是数据结构,我有点困惑。比如java.util中的HashMaps,它们是对象吗? (因为它的方法如put(),get(),我们不知道它们的内部工作原理)还是数据结构? (我一直认为它是数据结构,因为它是一个Map)。
字符串,它们是数据结构还是对象?
到目前为止,我编写的大多数代码都是所谓的“混合类”,它们也试图充当对象和数据结构。关于如何避免它们的任何提示?
答案 0 :(得分:22)
数据结构和类/对象之间的区别在Java中比在C ++中更难解释。在C中,没有类,只有数据结构,只不过是"容器"键入和命名字段。 C ++继承了这些"结构",所以你可以同时拥有" classic"数据结构和"真实对象"。
在Java中,你可以模仿"使用没有方法且只有公共字段的类的C风格数据结构:
public class VehicleStruct
{
public Engine engine;
public Wheel[] wheels;
}
VehicleStruct
的用户知道车辆的部件,并且可以直接与这些部件进行交互。行为即函数必须在类之外定义。这就是改变行为很容易的原因:添加新功能并不需要改变现有代码。另一方面,更改数据需要更改与VehicleStruct
交互的几乎所有功能。它违反了封装!
OOP背后的想法是隐藏数据并公开行为。它专注于您可以做的车辆,而无需知道它是否有发动机或安装了多少车轮:
public class Vehicle
{
private Details hidden;
public void startEngine() { ... }
public void shiftInto(int gear) { ... }
public void accelerate(double amount) { ... }
public void brake(double amount) { ... }
}
注意Vehicle
如何成为摩托车,汽车,卡车或坦克 - 你不需要知道细节。更改数据很容易 - 类外的人都不知道数据,因此不需要更改类的用户。改变行为很困难:当将新的(抽象)函数添加到类中时,必须调整所有子类。
现在,遵循&34;封装规则",您可以理解隐藏数据只是将字段设为私有并向VehicleStruct
添加访问方法:
public class VehicleStruct
{
private Engine engine;
private Wheel[] wheels;
public Engine getEngine() { return engine; }
public Wheel[] getWheels() { return wheels; }
}
在他的书中,鲍勃叔叔争辩说,通过这样做,你仍然有一个数据结构,而不是一个对象。您仍然只是将车辆建模为其零件的总和,并使用方法公开这些零件。它与具有公共字段和普通旧C struct
的版本基本相同 - 因此是数据结构。隐藏数据和公开方法不足以创建对象,您必须考虑方法是否实际公开行为或仅公开数据!
当你混合两种方法时,例如将getEngine()
与startEngine()
一起展示,您最终会得到一个"混合"。我手边没有马丁的书,但我记得他根本不推荐混合动力车,因为你最终得到了两个世界中最糟糕的东西:数据和行为都很难改变的对象。
您对HashMaps和字符串的疑问有点棘手,因为这些级别相当低,并且在您为应用程序编写的类中不太适合。尽管如此,使用上面给出的定义,您应该能够回答它们。
HashMap
是一个对象。它向您公开其行为并隐藏所有令人讨厌的散列细节。您告诉它put
和get
数据,并不关心使用哪种哈希函数,多少"桶和#34;有,以及如何处理碰撞。实际上,你只是通过HashMap
接口使用Map
,这是抽象的一个很好的指示,并且真正的"对象。
不要对您可以使用地图的实例作为数据结构的替代品感到困惑!
// A data structure
public class Point {
public int x;
public int y;
}
// A Map _instance_ used instead of a data structure!
Map<String, Integer> data = new HashMap<>();
data.put("x", 1);
data.put("y", 2);
另一方面,String
几乎是一个字符数组,并不试图隐藏它。我想有人可以称之为数据结构,但说实话,我不确定是否可以通过这种方式获得更多。
答案 1 :(得分:4)
对象是类的实例。 课程可以模拟现实世界中的各种事物。它是某种东西的抽象(汽车,插座,地图,连接,学生,老师,你的名字)。
数据结构是以某种方式组织某些数据的结构。 您可以通过使用类来实现不同的结构(这是您在不支持OOP的语言中所做的事情;例如,您仍然可以在C中实现数据结构)。 / p>
java中的HashMap是一个使用基于哈希的实现对地图数据结构建模的类,这就是为什么它被称为HashMap。
java中的套接字是一个不对数据结构进行建模但是其他东西(套接字)的类。
答案 2 :(得分:3)
正如我所看到的,Robert Martin试图传达的是,对象不应该通过getter和setter公开他们的数据,除非他们的唯一目的是充当简单的数据容器。这种容器的好例子可能是java bean,实体对象(来自DB实体的对象映射)等等。
但是,Java Collection Framework类并不是他所指的好例子,因为它们并没有真正公开它们的内部数据(在很多情况下是基本数组)。它提供了抽象,允许您检索它们包含的对象。因此(在我的POV中)它们适合“对象”类别。原因是你从书中添加的引号所说明的,但是有更好的理由可以避免暴露内部。例如,提供getter和setter的类会违反Demeter法。最重要的是,了解某个类的状态结构(知道它具有哪些getter / setter)会降低抽象该类实现的能力。还有更多原因。
答案 3 :(得分:3)
我相信这就是罗伯特。 C.马丁试图传达:
数据结构是简单地充当结构化数据容器的类。例如:
public class Point {
public double x;
public double y;
}
另一方面,对象用于创建抽象。 抽象被理解为:
下进行的更为复杂的简化
因此,对象隐藏了所有基础,只允许您以简化的方式操纵其数据的本质。例如:
public interface Point {
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
我们不知道Point是如何实施的,但我们知道如何消费。
答案 4 :(得分:1)
数据结构实际上是某些数据的结构化表示。它没有任何内置的知识&#34;除了数据的结构和命名。 对象更加通用,实际上几乎可以是系统中提供交互界面的任何实体,并且可以在不同的上下文中使用。具体而言,传统的类对象可能包含用于访问数据的数据和合适的方法,并且该数据可以是特定于对象实例的(每个实例)或类级别。
我不确定术语&#34;混合类&#34;基于作为对象或数据结构的描述,因为类通常包括数据。所以术语似乎是多余的。
答案 5 :(得分:1)
数据结构只是一种抽象,是一种表示数据的特殊方式。它们只是人造的结构,有助于降低高级别的复杂性,即不能在低级别工作。对象似乎意味着相同的东西,但对象和数据结构之间的主要区别在于对象可能抽象任何东西。它还提供行为。数据结构没有任何行为,因为它只是数据保持内存。
库类,如Map,List等。是类,表示数据结构。它们实现并设置数据结构,以便您可以通过创建它们的实例(即对象)轻松地在程序中使用它们。
答案 6 :(得分:0)
数据结构(DS)是一种抽象的方式,表示结构包含一些数据&#39;。具有一些键值对的HashMap是Java中的数据结构。 PHP中的关联数组类似。对象略低于DS级别。您的hashmap是一种数据结构。现在使用一个hashmap创建一个&#39;对象&#39;它使用put方法向该对象添加数据。我可以拥有自己的类Employee,它有数据,因此对我来说是DS。但要使用此DS执行某些操作,例如,如果员工是男性或女性同事,我需要一个员工实例并测试其性别属性。
不要将对象与数据结构混淆。
答案 7 :(得分:-1)
您的问题被标记为Java,因此我将在此处仅引用Java。 对象是Java中的Eve类;也就是说Java中的所有东西都扩展了Object而object是一个类。
因此,所有数据结构都是对象,但并非所有对象都是数据结构。
差异的关键是术语封装。
使用Java创建对象时,最佳做法是将所有数据成员设为私有。这样做是为了保护他们免受使用该类的任何人的影响。
但是,您希望人们能够访问数据,有时会更改数据。因此,您提供了称为访问器和更改器的公共方法,以允许它们这样做,也称为getter和setter。此外,您可能希望它们以您选择的格式作为整体查看对象,因此您可以定义toString方法;这将返回表示对象数据的字符串。
结构略有不同。
这是一堂课。
它是一个对象。
但它通常是在另一个班级内私人;由于Node在树中是私有的,因此不应该直接访问树的用户。但是,在树对象内部,节点数据成员是公开可见的。节点本身不需要访问器和增变器,因为这些函数受树对象的信任和保护。
研究关键词:封装,可见性修饰语
答案 8 :(得分:-1)
对象是类的实例。类可以定义该类的每个实例/对象继承的一组属性/字段。数据结构是一种组织和存储数据的方法。从技术上讲,数据结构是一个对象,但它是一个特定用于保存其他对象的对象(Java中的所有东西都是对象,甚至是原始类型)。
要回答您的问题,String是一个对象和一个数据结构。您创建的每个String对象都是String类的实例。 String,就像Java在内部表示的那样,本质上是一个字符数组,而数组是一个数据结构。
并非所有类都是数据结构的蓝图,但是所有数据结构在技术上都是对象的AKA实例(专门用于存储数据),如果这有意义的话。