我一直在阅读《 清洁代码:敏捷软件技巧手册》 ,在第六章第95-98页中阐明了对象和数据结构之间的区别:
对象将其数据隐藏在抽象之后,并公开对该数据进行操作的函数。数据结构公开其数据,并且没有有意义的功能。
对象公开行为并隐藏数据。这使得在不更改现有行为的情况下添加新的对象变得容易。这也使得很难向现有对象添加新行为。
数据结构公开数据并且没有重大行为。这使向现有数据结构添加新行为变得容易,但向现有功能添加新数据结构变得困难。
对于某些类是对象还是数据结构,我有些困惑。例如说java.util中的HashMap,它们是对象吗?(由于其诸如put(),get()之类的方法,我们不知道它们的内部工作原理)还是它们的数据结构?(我一直认为它是数据结构,因为它是Map)。
字符串也是如此,它们是数据结构还是对象?
到目前为止,我编写的大多数代码都是所谓的“混合类”,它们试图同时充当对象和数据结构。关于如何避免它们的任何提示?
在Java中比在C 中更难解释数据结构和类/对象之间的区别。在C语言中,没有类,只有数据结构,无非是类型字段和命名字段的“容器”。C 继承了这些“结构”,因此您可以同时拥有“经典”数据结构和“真实对象”。
在Java中,您可以使用没有方法并且只有公共字段的类“模拟” C样式的数据结构:
public class VehicleStruct { public Engine engine; public Wheel[] wheels; }
使用者VehicleStruct了解车辆的零件,并可以直接与这些零件交互。行为,即功能,必须在类之外定义。这就是为什么更改行为很容易的原因:添加新功能不需要更改现有代码。另一方面,更改数据实际上需要更改与交互的每个功能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可能是摩托车,汽车,卡车或油箱-您无需了解详细信息。更改数据很容易- 班级以外的人都不了解数据,因此无需更改该类的用户。更改行为很困难:在向类添加新(抽象)函数时,必须调整所有子类。
Vehicle
现在,按照“封装规则”,您可以理解隐藏数据只是将字段设为私有并将访问器方法添加到VehicleStruct:
public class VehicleStruct { private Engine engine; private Wheel[] wheels; public Engine getEngine() { return engine; } public Wheel[] getWheels() { return wheels; } }
鲍勃叔叔在他的书中认为,通过这样做,您仍然具有数据结构而不是对象。您仍然只是将车辆建模为零件的总和,并使用方法公开这些零件。它与具有公共字段和普通旧C的版本基本相同struct-因此是数据结构。隐藏数据和公开方法不足以创建对象,您必须考虑这些方法实际上是公开 行为 还是仅公开数据!
struct
当您将两种方法混合使用时(例如getEngine()与一起使用)startEngine(),最终会出现“混合”现象。我手头没有马丁书,但我记得他根本不推荐混合动力车,因为最终会遇到两全其美的局面:数据和行为都难以改变的对象。
getEngine()
startEngine()
您对HashMaps和Strings的问题有些棘手,因为它们的级别很低,并且不太适合您要为应用程序编写的类。但是,使用上面给出的定义,您应该能够回答它们。
A HashMap是一个对象。它向您展示其行为,并隐藏所有令人讨厌的哈希详细信息。你告诉它put和get数据,并不在乎其散列函数被使用,多少个“桶”有,而且冲突的处理方式。实际上,您HashMap仅通过其Map接口使用,这很好地表示了抽象和“真实”对象。
HashMap
put
get
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);
String另一方面,A 几乎是一个字符数组,并且不会尝试将其隐藏得太多。我想可以将其称为数据结构,但是老实说,我不确定是否可以通过一种方法或其他方法获得大量收益。
String