简体   繁体   English

对象和数据结构之间的区别是什么?

[英]Whats the difference between objects and data structures?

I've been reading the book Clean Code: A Handbook of Agile Software Craftsmanship and in chapter six pages 95-98 it clarifies about the differences between objects and data structures: 我一直在读“ 清洁代码:敏捷软件工艺手册 ”一书,在第六章第95-98页中,它阐明了对象和数据结构之间的区别:

  • Objects hide their data behind abstractions and expose functions that operate on that data. 对象将其数据隐藏在抽象之后,并公开对该数据进行操作的函数。 Data structures expose their data and have no meaningful functions. 数据结构公开其数据并且没有有意义的功能。

  • Object expose behavior and hide data. 对象公开行为并隐藏数据。 This makes it easy to add new kinds of objects without changing existing behaviors. 这使得在不改变现有行为的情况下添加新类型的对象变得容易。 It also makes it hard to add new behaviors to existing objects. 它还使得很难向现有对象添加新行为。

  • Data structures expose data and have no significant behavior. 数据结构公开数据并且没有重要行为。 This makes it easy to add new behaviors to existing data structures but makes it hard to add new data structures to existing functions. 这使得向现有数据结构添加新行为变得容易,但却难以向现有函数添加新数据结构。

I'm a tad bit confused whether some classes are objects or data structures. 对于某些类是对象还是数据结构,我有点困惑。 Say for example HashMaps in java.util, are they objects? 比如java.util中的HashMaps,它们是对象吗? (because of its methods like put(), get(), we dont know their inner workings) or are they data structures? (因为它的方法如put(),get(),我们不知道它们的内部工作原理)还是数据结构? (I've always thought of it as data structures because its a Map). (我一直认为它是数据结构,因为它是一个Map)。

Strings as well, are they data structures or objects? 字符串也是数据结构或对象吗?

So far majority of the code I've been writing have been the so called "hybrid classes" which try to act as an object and a data structure as well. 到目前为止,我编写的大多数代码都是所谓的“混合类”,它们也试图充当对象和数据结构。 Any tips on how to avoid them as well? 关于如何避免它们的任何提示?

The distinction between data structures and classes/objects is a harder to explain in Java than in C++. 数据结构和类/对象之间的区别在Java中比在C ++中更难解释。 In C, there are no classes, only data structures, that are nothing more than "containers" of typed and named fields. 在C中,没有类,只有数据结构,它们只不过是类型和命名字段的“容器”。 C++ inherited these "structs", so you can have both "classic" data structures and "real objects". C ++继承了这些“结构”,因此您可以拥有“经典”数据结构和“真实对象”。

In Java, you can "emulate" C-style data structures using classes that have no methods and only public fields: 在Java中,您可以使用没有方法且只有公共字段的类来“模拟”C风格的数据结构:

public class VehicleStruct
{
    public Engine engine;
    public Wheel[] wheels;
}

A user of VehicleStruct knows about the parts a vehicle is made of, and can directly interact with these parts. VehicleStruct的用户知道车辆制造的部件,并且可以直接与这些部件交互。 Behavior, ie functions, have to be defined outside of the class. 行为即函数必须在类之外定义。 That's why it is easy to change behavior: Adding new functions won't require existing code to change. 这就是改变行为很容易的原因:添加新功能不需要更改现有代码。 Changing data, on the other hand, requires changes in virtually every function interacting with VehicleStruct . 另一方面,更改数据需要更改与VehicleStruct交互的几乎所有功能。 It violates encapsulation! 它违反了封装!

The idea behind OOP is to hide the data and expose behavior instead. OOP背后的想法是隐藏数据并暴露行为。 It focuses on what you can do with a vehicle without having to know if it has engine or how many wheels are installed: 它着重于您可以使用车辆做什么 ,而无需知道它是否有发动机或安装了多少车轮:

public class Vehicle
{
    private Details hidden;

    public void startEngine() { ... }
    public void shiftInto(int gear) { ... }
    public void accelerate(double amount) { ... }
    public void brake(double amount) { ... }
}

Notice how the Vehicle could be a motorcycle, a car, a truck, or a tank -- you don't need to know the details. 注意Vehicle如何成为摩托车,汽车,卡车或坦克 - 您不需要知道细节。 Changing data is easy -- nobody outside the class knows about data so no user of the class needs to be changed. 更改数据很容易 - 类外的人都不知道数据,因此不需要更改类的用户。 Changing behavior is difficult: All subclasses must be adjusted when a new (abstract) function is added to the class. 改变行为很困难:当向类中添加新的(抽象)函数时,必须调整所有子类。

Now, following the "rules of encapsulation", you could understand hiding the data as simply making the fields private and adding accessor methods to VehicleStruct : 现在,遵循“封装规则”,您可以理解将数据隐藏为简单地将字段设为私有并向VehicleStruct添加访问器方法:

public class VehicleStruct
{
    private Engine engine;
    private Wheel[] wheels;

    public Engine getEngine() { return engine; }
    public Wheel[] getWheels() { return wheels; }
}

In his book, Uncle Bob argues that by doing this, you still have a data structure and not an object. 在他的书中,鲍勃叔叔争辩说,通过这样做,你仍然有一个数据结构,而不是一个对象。 You are still just modeling the vehicle as the sum of its parts, and expose these parts using methods. 您仍然只是将车辆建模为其零件的总和,并使用方法公开这些零件。 It is essentially the same as the version with public fields and a plain old C struct -- hence a data structure. 它与具有公共字段和普通旧C struct的版本基本相同 - 因此是数据结构。 Hiding data and exposing methods is not enough to create an object, you have to consider if the methods actually expose behavior or just the data! 隐藏数据和公开方法不足以创建对象,您必须考虑方法是否实际暴露行为或仅仅是数据!

When you mix the two approaches, eg exposing getEngine() along with startEngine() , you end up with a "hybrid". 当您混合使用这两种方法时,例如将getEngine()startEngine()一起startEngine() ,最终会出现“混合”。 I don't have Martin's Book at hand, but I remember that he did not recommend hybrids at all, as you end up with the worst of both worlds: Objects where both data and behavior is hard to change. 我手头没有马丁的书,但我记得他根本不推荐混合动力车,因为你最终得到了两个世界中最糟糕的:数据和行为都很难改变的对象。

Your questions concerning HashMaps and Strings are a bit tricky, as these are pretty low level and don't fit quite well in the kinds of classes you will be writing for your applications. 你关于HashMaps和Strings的问题有点棘手,因为它们的级别很低,并且不适合你将为你的应用程序编写的类。 Nevertheless, using the definitions given above, you should be able to answer them. 尽管如此,使用上面给出的定义,您应该能够回答它们。

A HashMap is an object. HashMap是一个对象。 It exposes its behavior to you and hides all the nasty hashing details. 它向您公开其行为并隐藏所有令人讨厌的散列细节。 You tell it to put and get data, and don't care which hash function is used, how many "buckets" there are, and how collisions are handled. 你告诉它putget数据,并不关心使用哪个散列函数,有多少“桶”,以及如何处理冲突。 Actually, you are using HashMap solely through its Map interface, which is quite a good indication of abstraction and "real" objects. 实际上,你只是通过它的Map接口使用HashMap ,这是抽象和“真实”对象的一个​​很好的指示。

Don't get confused that you can use instances of a Map as a replacement for a data structure! 不要混淆,你可以使用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);

A String , on the other hand, is pretty much an array of characters, and does not try to hide this very much. 另一方面, String几乎是一个字符数组,并不试图隐藏它。 I guess one could call it a data structure, but to be honest I am not sure if much is to be gained one way or the other. 我想有人可以称之为数据结构,但说实话,我不确定是否可以通过这种方式获得更多。

An object is an instance of a class. 对象是类的实例。 A class can model various things from the real world. 课程可以模拟现实世界中的各种事物。 It's an abstraction of something (car, socket, map, connection, student, teacher, you name it). 它是某种东西的抽象(汽车,插座,地图,连接,学生,老师,你的名字)。

A data structure is a structure which organizes certain data in a certain way. 数据结构是以某种方式组织某些数据的结构。 You can implement structures in ways different that by using classes (that's what you do in languages which don't support OOP eg; you can still implement a data structure in C let's say). 您可以通过使用类来实现不同的结构(这是您在不支持OOP的语言中所做的事情;例如,您仍然可以在C中实现数据结构)。

HashMap in java is a class which models a map data structure using hash-based implementation, that's why it's called HashMap. java中的HashMap是一个使用基于哈希的实现对地图数据结构建模的类,这就是为什么它被称为HashMap。

Socket in java is a class which doesn't model a data structure but something else (a socket). java中的Socket是一个不对数据结构进行建模而是对其他东西(套接字)进行建模的类。

As I see it , what Robert Martin tries to convey, is that objects should not expose their data via getters and setters unless their sole purpose is to act as simple data containers. 正如我所看到的,罗伯特·马丁试图传达的是,对象不应该通过getter和setter公开他们的数据,除非他们唯一的目的是充当简单的数据容器。 Good examples of such containers might be java beans, entity objects (from object mapping of DB entities), etc. 这种容器的好例子可能是java bean,实体对象(来自DB实体的对象映射)等。

The Java Collection Framework classes, however, are not a good example of what he's referring to, since they don't really expose their internal data (which is in a lot of cases basic arrays). 但是,Java Collection Framework类并不是他所指的内容的一个很好的例子,因为它们并没有真正公开它们的内部数据(在很多情况下是基本数组)。 It provides abstraction that lets you retrieve objects that they contain. 它提供了抽象,允许您检索它们包含的对象。 Thus (in my POV) they fit in the "Objects" category. 因此(在我的POV中)它们适合“对象”类别。

The reasons are stated by the quotes you added from the book, but there are more good reasons for refraining from exposing the internals. 原因是你从书中添加的引号所说明的,但是有更好的理由可以避免暴露内部。 Classes that provide getters and setters invite breaches of the Law of Demeter, for instance. 例如,提供getter和setter的类会违反Demeter法。 On top of that, knowing the structure of the state of some class (knowing which getters/setters it has) reduces the ability to abstract the implementation of that class. 最重要的是,了解某个类的状态结构(知道它具有哪些getter / setter)会降低抽象该类实现的能力。 There are many more reasons of that sort. 这种情况还有很多原因。

This is what, I believe, Robert. 我相信这就是罗伯特。 C. Martin was trying to convey: C.马丁试图表达:

  1. Data Structures are classes that simply act as containers of structured data. 数据结构是简单地充当结构化数据容器的类。 For example: 例如:

     public class Point { public double x; public double y; } 
  2. Objects, on the other hand, are used to create abstractions. 另一方面,对象用于创建抽象。 An abstraction is understood as: 抽象被理解为:

    a simplification of something much more complicated that is going on under the covers The Law of Leaky Abstractions, Joel on Software 简化了一些更为复杂的内容,这些内容正在进行中。“漏洞抽象法则”,Joel on Software

    So, objects hide all their underpinnings and only let you manipulate the essence of their data in a simplified way. 因此,对象隐藏了所有基础,只允许您以简化的方式操纵数据的本质 For instance: 例如:

     public interface Point { double getX(); double getY(); void setCartesian(double x, double y); double getR(); double getTheta(); void setPolar(double r, double theta); } 

    Where we don't know how the Point is implemented , but we do know how to consume it. 我们不知道Point是如何实现的 ,但我们知道如何使用它。

A data structure is only an abstraction, a special way of representing data. 数据结构只是一种抽象,是一种表示数据的特殊方式。 They are just human-made constructs, which help in reducing complexity at the high-level, ie to not work in the low-level. 它们只是人造的结构,有助于降低高级别的复杂性,即不能在低级别工作。 An object may seem to mean the same thing, but the major difference between objects and data structures is that an object might abstract anything. 对象似乎意味着相同的东西,但对象和数据结构之间的主要区别在于对象可能抽象任何东西。 It also offers behaviour. 它还提供行为。 A data structure does not have any behaviour because it is just data-holding memory. 数据结构没有任何行为,因为它只是数据保持内存。

The libraries classes such as Map, List,etc. 库类,如Map,List等。 are classes, which represent data structures. 是类, 代表数据结构。 They implement and setup a data structure so that you can easily work with them in your programs by creating instances of them (ie objects). 它们实现并设置数据结构,以便您可以通过创建它们的实例(即对象)轻松地在程序中使用它们。

A data structure is literally a structured representation of some data. 数据结构实际上是一些数据的结构化表示。 It doesn't have any built-in "knowledge" other than the structure and naming of the data. 除了数据的结构和命名之外,它没有任何内置的“知识”。 An object is much more general and really could be almost any entity in your system that presents an interface for interaction and can be used in different contexts. 对象更加通用,实际上几乎可以是系统中提供交互接口的任何实体,并且可以在不同的上下文中使用。 Specifically, a traditional class object, for example, might contain data and suitable methods for accessing the data, and that data could be object instance-specific (per instance) or class level. 具体而言,传统的对象可能包含用于访问数据的数据和合适的方法,并且该数据可以是特定于对象实例的(每个实例)或类级别。

I'm unsure of the term "hybrid class" based upon the description of acting as an object or a data structure since a class often does include data. 基于作为对象或数据结构的描述,我不确定术语“混合类”,因为类经常包含数据。 So that terminology seems redundant. 所以这个术语似乎是多余的。

Data structures(DS) are an abstract way of saying that a structure holds some data'. 数据结构(DS)是一种表示结构保存某些数据的抽象方式。 HashMap with some key value pairs is a data structure in Java. 具有一些键值对的HashMap是Java中的数据结构。 Associated arrays are similarly in PHP etc. Objects is a little lower than the DS level. PHP中的关联数组类似。对象略低于DS级别。 Your hashmap is a data structure. 您的hashmap是一种数据结构。 now to use a hashmap you create an 'object' of it and add data to that object using put method. 现在使用散列映射创建它的“对象”并使用put方法将数据添加到该对象。 I can have my own class Employee which has data and is thus a DS for me. 我可以拥有自己的类Employee,它有数据,因此对我来说是DS。 But to use this DS to do some operations like o see if the employee is a male or a female colleague i need an instance of an Employee and test its gender property. 但是要使用此DS执行某些操作,例如,如果员工是男性或女性同事,我需要一个Employee实例并测试其性别属性。

Don't confuse objects with data structures. 不要将对象与数据结构混淆。

Your question is tagged as Java, so I will reference only Java here. 您的问题被标记为Java,因此我将在此处仅引用Java。 Objects are the Eve class in Java; 对象是Java中的Eve类; that is to say everything in Java extends Object and object is a class. 也就是说Java中的所有东西都扩展了Object而object是一个类。

Therefor, all data structures are Objects, but not all Objects are data structures. 因此,所有数据结构都是对象,但并非所有对象都是数据结构。

The key to the difference is the term Encapsulation. 差异的关键是术语封装。

When you make an object in Java, it is considered best practice to make all of your data members private. 使用Java创建对象时,最好将所有数据成员设为私有。 You do this to protect them from anyone using the class. 这样做是为了保护他们免受使用该类的任何人的影响。

However, you want people to be able to access the data, sometimes change it. 但是,您希望人们能够访问数据,有时可以更改数据。 So, you provide public methods called accessors and mutators to allow them to do so, also called getters and setters. 因此,您提供了称为访问器和更改器的公共方法,以允许它们这样做,也称为getter和setter。 Additionally, you may want them to view the object as a whole in a format of your choosing, so you can define a toString method; 此外,您可能希望它们以您选择的格式作为整体查看对象,因此您可以定义toString方法; this returns a string representing the object's data. 这将返回表示对象数据的字符串。

A structure is slightly different. 结构略有不同。

It is a class. 这是一堂课。

It is an Object. 它是一个对象。

But it is usually private within another class; 但它通常在另一个班级内是私人的; As a Node is private within a tree and should not be directly accessible to the user of the tree. 由于Node在树中是私有的,因此不应该直接访问树的用户。 However, inside the tree object the nodes data members are publicly visible. 但是,在树对象内部,节点数据成员是公开可见的。 The node itself does not need accessors and mutators, because these functions are trusted to and protected by the tree object. 节点本身不需要访问器和增变器,因为这些函数受树对象的信任和保护。

Keywords to research: Encapsulation, Visibility Modifiers 研究关键词:封装,可见性修饰符

An object is an instance of a class. 对象是类的实例。 A class can define a set of properties/fields that every instance/object of that class inherits. 类可以定义该类的每个实例/对象继承的一组属性/字段。 A data structure is a way to organize and store data. 数据结构是一种组织和存储数据的方法。 Technically a data structure is an object, but it's an object with the specific use for holding other objects (everything in Java is an object, even primitive types). 从技术上讲,数据结构是一个对象,但它是一个特定用于保存其他对象的对象(Java中的所有东西都是对象,甚至是原始类型)。

To answer your question a String is an object and a data structure. 为了回答你的问题,String是一个对象一个数据结构。 Every String object you create is an instance of the String class. 您创建的每个String对象都是String类的实例。 A String, as Java represents it internally, is essentially a character array, and an array is a data structure. String,就像Java在内部表示的那样,本质上是一个字符数组,一个数组是一个数据结构。

Not all classes are blueprints for data structures, however all data structures are technically objects AKA instances of a class (that is specifically designed to store data), if that makes any sense. 并非所有类都是数据结构的蓝图,但是所有数据结构在技术上都是对象的AKA实例(专门用于存储数据),如果这有意义的话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM