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

Hoo*_*lum 39 java language-agnostic oop object data-structures

我一直在读" 清洁代码:敏捷软件工艺手册 "一书,在第六章第95-98页中,它阐明了对象和数据结构之间的区别:

  • 对象将其数据隐藏在抽象之后,并公开对该数据进行操作的函数.数据结构公开其数据并且没有有意义的功能.

  • 对象公开行为并隐藏数据.这使得在不改变现有行为的情况下添加新类型的对象变得容易.它还使得很难向现有对象添加新行为.

  • 数据结构公开数据并且没有重要行为.这使得向现有数据结构添加新行为变得容易,但却难以向现有函数添加新数据结构.

对于某些类是对象还是数据结构,我有点困惑.比如java.util中的HashMaps,它们是对象吗?(因为它的方法如put(),get(),我们不知道它们的内部工作原理)还是数据结构?(我一直认为它是数据结构,因为它是一个Map).

字符串也是数据结构或对象吗?

到目前为止,我编写的大多数代码都是所谓的"混合类",它们也试图充当对象和数据结构.关于如何避免它们的任何提示?

Fer*_*yer 32

数据结构和类/对象之间的区别在Java中比在C++中更难解释.在C中,没有类,只有数据结构,它们只不过是类型和命名字段的"容器".C++继承了这些"结构",因此您可以拥有"经典"数据结构和"真实对象".

在Java中,您可以使用没有方法且只有公共字段的类来"模拟"C风格的数据结构:

public class VehicleStruct
{
    public Engine engine;
    public Wheel[] wheels;
}
Run Code Online (Sandbox Code Playgroud)

用户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) { ... }
}
Run Code Online (Sandbox Code Playgroud)

注意Vehicle摩托车,汽车,卡车或坦克怎么样 - 你不需要知道细节.更改数据很容易 - 类外的人都不知道数据,因此不需要更改类的用户.改变行为很困难:当向类中添加新的(抽象)函数时,必须调整所有子类.

现在,遵循"封装规则",您可以理解将数据隐藏为仅将字段设为私有并将访问器方法添加到VehicleStruct:

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

    public Engine getEngine() { return engine; }
    public Wheel[] getWheels() { return wheels; }
}
Run Code Online (Sandbox Code Playgroud)

在他的书中,鲍勃叔叔争辩说,通过这样做,你仍然有一个数据结构,而不是一个对象.您仍然只是将车辆建模为其零件的总和,并使用方法公开这些零件.它与具有公共字段和普通旧C的版本基本相同struct- 因此是数据结构.隐藏数据和公开方法不足以创建对象,您必须考虑方法是否实际暴露行为或仅仅是数据!

当你混合使用这两种方法时,例如getEngine()与之一起曝光startEngine(),你就会得到一个"混合".我手头没有马丁的书,但我记得他根本不推荐混合动力车,因为你最终得到了两个世界中最糟糕的:数据和行为都很难改变的对象.

您对HashMaps和字符串的问题有点棘手,因为它们的级别相当低,并且在您为应用程序编写的类中不太适合.尽管如此,使用上面给出的定义,您应该能够回答它们.

A HashMap是一个对象.它向您公开其行为并隐藏所有令人讨厌的散列细节.你告诉它putget数据,并不关心使用哪个哈希函数,有多少"桶",以及如何处理冲突.实际上,你HashMap只是通过它的Map界面使用,这是抽象和"真实"对象的一个​​很好的指示.

不要混淆你可以使用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);
Run Code Online (Sandbox Code Playgroud)

String另一方面,A 几乎是一个字符数组,并不试图隐藏它.我想有人可以称之为数据结构,但说实话,我不确定是否可以通过这种方式获得更多.

  • 很好的解释@ferdinard,谢谢!我发现了这篇文章 - https://hackernoon.com/objects-vs-data-structures-e380b962c1d2 它使用了你所有的详细解释示例。 (2认同)

Enr*_*que 5

我相信,这就是罗伯特。C. 马丁试图传达:

  1. 数据结构是简单地充当结构化数据容器的类。例如:

    public class Point {
        public double x;
        public double y;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 另一方面,对象用于创建抽象。一个抽象被理解为:

    对隐藏的更复杂的事情的简化The Law of Leaky Abstractions, Joel on Software

    因此,对象隐藏了它们的所有基础,只能让您以简化的方式操作其数据的本质。例如:

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

    我们不知道 Point 是如何实现的,但我们知道如何使用它。

  • Martin 这本书的精妙之处在于,你的界面 `Point` 仍然暴露了它的部分,而不是行为。它的任何方法都不允许您对这一点做一些有意义的事情!我没有说这是不好的,一个点可能是一个经典的例子,何时更喜欢对象的数据结构,但这可能不是最好的例子。 (2认同)