扩展一个类还是直接修改它更好?
因此,我正在致力于用 Java 创建数据结构的可视化。我已经开始实现数据结构(二叉搜索树),但我需要向包含的节点类添加一些附加功能。就约定和最佳实践而言,我应该创建具有此附加功能的节点的子类,还是应该修改我所拥有的内容并将其记录在那里?
我的问题与此处提出的问题类似有点超出我的头了。
我知道这对于我正在做的事情可能并不重要,所以我将这个问题作为一般性问题来问。
编辑:我可能应该更清楚。我的修改实际上并没有改变原始实现,只是添加了几个额外的字段(x 和 y 坐标加上一个布尔值来设置该节点是否突出显示)和访问/修改这些字段的函数。此外,我正在使用的节点类也包含在 BST 实现中。
从阅读您的答案来看,似乎对于这两种情况都有争论。我同意创建一个单独的类或接口通常可能是最好的事情。创建另一个类似乎会变得很棘手,因为您仍然需要一种从节点中提取数据的方法。我使用的 BST 实现是通用的,Node 类或 BST 类本身没有任何此类功能来返回数据,所以至少我必须添加它。
感谢您提供信息丰富的回复。
So I'm working on creating a visualization for a data structure in Java. I already have the implementation of the data structure (Binary Search Tree) to start with, but I need to add some additional functionality to the included node class. As far as conventions and best practices are concerned, should I create a subclass of the node with this added functionality or should I just modify what I have and document it there?
My question is similar to what's asked here but that's a little over my head.
I know it probably doesn't matter much for what I'm doing, so I'm asking this more as a general thing.
Edit: I probably should have been more clear. My modifications don't actually change the original implementation other than to add a couple of extra fields (x and y coords plus a boolean to set whether that node is highlighted) and functions to access/modify those fields. Also the node class I'm working with is included in the BST implementation
From reading your answers it seems like there's arguments to be made for either case. I agree that creating a separate class or interface is probably the best thing to do in general. Creating another class seems like it could get tricky since you'd still need a way to extract the data out of the node. The BST implementation I'm using is generic and doesn't have any such functionality by itself in the Node class or the BST class to just return the data so at minimum I have to add that.
Thanks for the informative replies.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
混合逻辑上独立的功能会导致混乱。子类化是一种非常特殊的关系,经常被过度使用。子类化适用于 Is-a-Kind 关系。
如果你想可视化某些东西,为什么不为此创建一个完全独立的类呢?您可以简单地将 Node 对象传递给它。 (或者更好的是,使用接口。)
Mixing up logically independent functionalities will cause a mess. Subclassing is a very special relationship, often overused. Subclassing is for Is-a-Kind relationships.
If you want to visualize something, why not create a fully independent Class for that? You could simply pass your Node object to this. (Or even better, use an Interface.)
要回答的问题是,当您不可视化数据结构时,“基本功能”是否有用,甚至是不需要的?
您甚至可能根本不想延长课程。如果没有更多细节,在我看来,你有一个有效的数据结构。您可以创建一个知道如何可视化它的新类。
也就是说,您拥有一个数据结构和另一个知道如何可视化数据结构的类,而不是知道如何可视化自身的数据结构。哎呀——你可能会发现它演变成另一个完整的类层次结构,因为你可能需要可视化队列、堆栈等。与你的二叉搜索树无关。
The question to answer is, is the 'base functionality' useful, even disirable, when you're not visualizing the data structure?
You might not even want to extend the class at all. Without more detail, it seems to me that you have a datastructure that works. You could create a NEW class that knows how to vizualise it.
That is, instead of a datastructure than knows how to visualize itself, you have a datastructure, and another class that knows how to visualize the datastructure. Heck - you may find that that evolves into another whole class hierarchy because you might need to visualize queues, stacks, etc. etc. NOTHING to do wiht your binary search tree.
既然您问的是一般情况,那么简短的回答是:这实际上取决于具体情况。
首先,假设子类与其父类具有“IS-A”关系。如果您不能说您的新子类是原始类的特定类型,那么您就问了错误的问题,并且应该创建一个新的、不相关的类。
在你的具体情况下,我同意n8wrl;由于可视化与数据结构无关,因此实现一个完整的单独的 Visualized 接口可能比创建一个 DrawableBSTNode 子类更好。
Since you're asking in general, here's the short answer: it really depends on the situation.
First off, subclasses are assumed to have an "IS-A" relationship with their parent classes. If you can't say that your new subclass IS A specific kind of the original class, you're asking the wrong question, and should be making a new, unrelated class.
In your specific case, I agree with n8wrl; since visualization has nothing to do with data structures, it's probably better to implement a whole separate
Visualizable
interface than make aDrawableBSTNode
subclass.我想说,在向现有实现添加功能的一般情况下,您应该扩展现有实现而不是修改它。
这是我的推理。如果该节点在二叉搜索树实现之外的任何地方使用,那么当您修改它时,您需要找到使用它的所有地方,以确保这些地方不会与您的修改发生冲突。虽然仅以新方法的形式添加功能通常不会导致问题,但它可能会导致问题。你永远不知道一个物体是如何使用的。
其次,即使它仅在二叉搜索树中使用,您仍然需要确保 BST 的实现能够很好地配合您的修改。
最后,如果您确实扩展了它,则不必担心第一点和第二点。而且您还可以获得额外的好处,即您的修改始终与原始实现分开。这将使您更容易跟踪您所做的事情并对其进行评论。
I would say that in the general case of adding functionality to an existing implementation, you should extend the existing implementation rather than modify it.
And here's my reasoning. If that node is used anywhere aside from the Binary Search Tree implementation, then when you modify it you'll need to find everywhere it is used to ensure that none of those places conflict with your modifications. While just adding functionality in the form of new methods generally won't cause problems, it could cause problems. You never know how an object is used.
Second, even if it is only used in the Binary Search Tree, you'll still need to make sure that the BST's implementation will play nice with your modifications.
Finally, if you do extend it, you don't have to worry about points one and two. And you get the added bonus of having your modifications kept separate from the original implementation for all time. This will make it easier to track what you have done and comment on it.
没有简单的答案,随着时间的推移,您必须学习了解何时以及如何添加功能。
仅添加到基类似乎是简单的解决方案,但它会污染您的基类。如果这是一个类,您可以合理地期望另一个程序(甚至您的程序的一部分)使用您要添加的功能在您的类职责的上下文中是否有意义?如果没有,这可能是一个糟糕的举动。您是否添加了将基类链接到特定用途的依赖项?因为如果你是这样,那就会把代码重用扔到窗外。
继承是很多工程师都倾向于采用的解决方案,而且这是一条诱人的途径。但随着我成长为一名工程师,我很少使用它。继承只能用在真正的 is-a 关系中,并且您需要尊重行为亚型
不然你以后会后悔的。由于 Java 只允许单继承,这意味着您只能进行一次子类型化。
组合(尤其是接口)通常是一个更好的主意。通常,看似“是”的关系实际上是“有”的关系。或者有时您真正需要的只是一个辅助类,它具有许多将原始类作为参数的函数。
然而,组合存在一个问题,即要将这些对象存储在树中。这里的解决方案是接口。您不需要存储节点的树。您想要具有可以为您提供节点的接口的对象。
你的节点类是一个 HasNode, getNode 只是返回它。您的 NodeVisualizer 类也是一个 HasNode,现在您也可以将 NodeVisualizer 存储在树中。当然,现在您遇到了另一个问题,您的树可能包含 NodeVisualizers 和 Nodes,这不太好。另外,当您从树函数返回 HasNode 时,您必须将它们转换为正确的实例,这很丑陋。您需要为此使用模板,但这是另一个答案。
There's no simple answer, knowing when and how to add functionality is a something you have to learn over time.
Just adding to the base class seems like the easy solution, but it's polluting your base class. If this is a class you could reasonably expect another program (or even part of your program) to use does the functionality you are adding make sense in the context of your class's responsibility? If it doesn't this is probably a bad move. Are you adding dependencies linking your base class to your specific use? Because if you are that's throwing code reuse right out the window.
Inheriting is the solution a lot of engineers gravitate to, and it's a seductive route. But as I've grown as an engineer it's one that I use sparingly. Inheritance should only be used in true is-a relationships, and you need to respect behavioral subtyping
or you are going to regret it later on. And since Java only allows single inheritance it means you only get one shot at subtyping.
Composition (especially with interfaces) is often a better idea. Often what looks like a is-a relationship is really a has-a one. Or sometimes all you really need is a helper class, that has many functions that take your original class as an argument.
However with composition there is one issue, want to store these objects in your tree. The solution here is interfaces. You don't want a tree that stores Nodes. You want to objects that have an interface that can give you a node.
Your node class is a HasNode with getNode just returning this. Your NodeVisualizer class is also a HasNode, and now you can store NodeVisualizers in your tree as well. Of course now you have another problem, your tree could contain NodeVisualizers and Nodes, and that wouldn't be good. Plus when you get a HasNode back from the tree functions you have to cast them to the right instance and that's ugly. You'll want to use templates for that, but that's another answer.