4

所以我正在努力为 Java 中的数据结构创建可视化。我已经开始实现数据结构(二叉搜索树),但我需要向包含的节点类添加一些额外的功能。就约定和最佳实践而言,我应该创建一个具有此附加功能的节点的子类,还是应该只修改我拥有的并在那里记录它?

我的问题类似于这里提出的问题,但这有点超出我的想象。

我知道这对我正在做的事情可能并不重要,所以我更多地要求这个作为一般性的事情。

编辑:我可能应该更清楚。我的修改实际上并没有改变原始实现,只是添加了几个额外的字段(x 和 y 坐标加上一个布尔值来设置是否突出显示该节点)和访问/修改这些字段的函数。我正在使用的节点类也包含在 BST 实现中

从阅读您的答案看来,无论哪种情况都需要提出论据。我同意创建一个单独的类或接口通常是最好的做法。创建另一个类似乎会变得很棘手,因为您仍然需要一种从节点中提取数据的方法。我正在使用的 BST 实现是通用的,并且在 Node 类或 BST 类中本身没有任何此类功能来仅返回数据,因此至少我必须添加它。

感谢您提供信息丰富的回复。

4

5 回答 5

12

要回答的问题是,当您不可视化数据结构时,“基本功能”是否有用,甚至不受欢迎?

您甚至可能根本不想扩展该类。没有更多细节,在我看来你有一个有效的数据结构。您可以创建一个知道如何对其进行可视化的新类。

也就是说,不是一个知道如何可视化自身的数据结构,而是一个数据结构和另一个知道如何可视化数据结构的类。哎呀-您可能会发现这会演变成另一个完整的类层次结构,因为您可能需要可视化队列、堆栈等等等。对您的二叉搜索树无能为力。

于 2010-04-28T16:25:15.217 回答
3

既然你问的是一般情况,这里是简短的回答:这真的取决于情况

首先,假设子类与其父类具有“IS-A”关系。如果你不能说你的新子类是原始类的一种特定类型,那么你问错了问题,应该创建一个新的、不相关的类。

  • 如果新代码与类的核心目的密切相关,并且适用于类的所有成员(例如所有 BST),那么修改可能会更好。高凝聚力是好的。
  • 如果您的新代码与类的核心目的相关,但只与该类型的一些对象有关(例如,只有平衡的 BST),子类化可能是要走的路。
  • 根据您要更改的内容、您的代码使用了多少地方、有多少不同的人/组织正在使用它等等,您的更改可能会导致其他代码出现意外行为,因此您应该在修改现有代码之前三思而后行。这并不意味着自动对常用事物进行子类化;由于上述原因,这通常是错误的。

在您的具体情况下,我同意 n8wrl;由于可视化与数据结构无关,因此实现一个完全独立的Visualizable接口可能比创建一个DrawableBSTNode子类更好。

于 2010-04-28T16:57:42.390 回答
2

我想说,在向现有实现添加功能的一般情况下,您应该扩展现有实现而不是修改它。

这是我的理由。如果该节点在除二叉搜索树实现之外的任何地方使用,那么当您修改它时,您需要找到它用于确保这些地方没有与您的修改冲突的任何地方。虽然仅以新方法的形式添加功能通常不会导致问题,但可能会导致问题。你永远不知道一个对象是如何被使用的。

其次,即使它只在二叉搜索树中使用,您仍然需要确保 BST 的实现能够很好​​地配合您的修改。

最后,如果你扩展它,你不必担心第一点和第二点。您还可以获得额外的好处,即您的修改始终与原始实现分开。这将使您更容易跟踪您所做的事情并对其发表评论。

于 2010-04-28T16:22:30.967 回答
2

没有简单的答案,知道何时以及如何添加功能是您必须随着时间的推移而学习的东西。

只是添加到基类似乎是一个简单的解决方案,但它会污染你的基类。如果这是一个类,您可以合理地期望另一个程序(甚至您的程序的一部分)使用您添加的功能在您的类职责的上下文中是否有意义?如果不是这样,这可能是一个糟糕的举动。您是否添加了将基类链接到您的特定用途的依赖项?因为如果你是这样的话,那就是把代码重用扔到窗外了。

继承是许多工程师倾向于采用的解决方案,而且是一条诱人的路线。但随着我成长为一名工程师,我很少使用它。继承应该只用在真正的 is-a 关系中,你需要尊重行为子类型 ,否则你以后会后悔的。而且由于 Java 只允许单一继承,这意味着您只能进行一次子类型化。

组合(尤其是接口)通常是一个更好的主意。通常看起来像是一种关系的关系实际上是一种拥有的关系。或者有时你真正需要的只是一个辅助类,它有许多将你的原始类作为参数的函数。

然而,组合存在一个问题,希望将这些对象存储在您的树中。这里的解决方案是接口。你不想要一棵存储节点的树。您想要具有可以为您提供节点的接口的对象。

public interface HasNode {
    public Node getNode();
}

你的节点类是一个 HasNode , getNode 只是返回这个。您的 NodeVisualizer 类也是 HasNode,现在您也可以在树中存储 NodeVisualizer。当然现在你有另一个问题,你的树可能包含 NodeVisualizers 和 Nodes,这不是很好。另外,当您从树函数中获取 HasNode 时,您必须将它们强制转换为正确的实例,这很丑陋。您需要为此使用模板,但这是另一个答案。

于 2010-04-28T21:21:06.933 回答
0

混淆逻辑上独立的功能会导致混乱。子类化是一种非常特殊的关系,经常被过度使用。子类化适用于 Is-a-Kind 关系。

如果你想可视化某些东西,为什么不为此创建一个完全独立的类呢?您可以简单地将您的 Node 对象传递给它。(或者更好的是,使用接口。)

于 2010-04-28T18:38:56.467 回答