对象内的链接是否被视为反模式?
假设您有一个经常(甚至专门)用作链接列表一部分的类。将链接信息放置在对象内是否是一种反模式?
例如:
public class Item { private Item prev; private Item next; ... }
经常引用的建议是简单地使用通用容器类(例如 Java 中的 java.util.LinkedList),但这会产生拥有单独节点对象(以及链接的节点对象)的开销。对象不能轻易引用其兄弟姐妹)。
想法?
Suppose you have a class that is frequently (or even exclusively) used as part of a linked list. Is it an anti-pattern to place the linkage information within the object?
For example:
public class Item { private Item prev; private Item next; ... }
An often-cited recommendation is to simply use a generic container class (such as java.util.LinkedList
in Java), but this creates the overhead of having a separate node object (and the linked object cannot readily refer to its siblings).
Thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
它不一定是反模式。反模式必须具有负面影响才能赢得“反”的权利。
例如,
Tree
数据结构中的Node
将需要将其链接缓存在Node
内部。其他任何事情都会违反基于对象责任的数据和代码的封装和本地化这一更重要的概念。另一方面,嵌入“下一个”客户的
Customer
数据结构意味着Customer
数据结构正在处理两个不相关的职责,即维护客户
数据,以及维护客户
列表数据结构的数据。在这种情况下,这两种职责可能会以影响维护便利性的方式混合在一起;因此,将被视为一种反模式。It is not necessarily an anti-pattern. Anti-patterns must have negative side-effects to earn the right to the "anti".
For example, a
Node
in aTree
data structure would need it's linkage cached inside of theNode
. Anything else would violate the much more important concept of encapsulation and localization of data and code based on responsibility of the object.On the other hand, a
Customer
data structure that embeds its "next" customer would imply that theCustomer
data structure is handling two unrelated responsibilities, that of maintaining theCustomer
data, and that of maintaining theCustomer
's list data structure. In such a scenario, the two responsibilities could intermingle in ways that impact the ease of maintenance; and hence, would be seen as an anti-pattern.我想是的。在我看来,您正在混合职责(例如,如果您的对象反映员工,我希望只看到与员工相关的属性和方法,而不是与链接列表相关的方法和属性)。
有时,一点点开销就是“更干净”设计的成本。您是否愿意支付这些管理费用是另一个问题。在我看来,使用内置链表等实用程序所增加的一点开销是值得的……它节省了开发时间,经过了彻底的测试,并实现了更简洁的设计。
I think so. It seems to me that you're mixing responsibilities (e.g. if your objects reflect employees, I'd expect to only see employee related properties and methods, not methods and properties related to linked lists).
Sometimes a little overhead is the cost of having "cleaner" designs. Whether or not you're willing to pay for that overhead is a different question. In my opinion, the little overhead added by using utilities like the built-in linked lists is worth it... it saves development time, is thoroughly tested and makes for a cleaner design.
如果它不总是在链接列表中使用,那么它就是一个反模式。如果您向您的类添加可能需要的属性/方法,您最终将拥有一支瑞士军队。了解YAGNI。
添加这些方法也会破坏 SRP,因为该项目还将负责跟踪其同级项目。
It's an anti pattern if it's not always used in a linked list. You'll end up with a swiss army if you add properties/methods to your classes that you might need. Read about YAGNI.
Adding those methods will also break SRP since the item will also be responsible of keeping track of it's siblings.
一般来说,建议不要这样做,因为您将来需要的功能会不断增加。即使您目前不需要“搜索”和“排序”等功能,有一天规格会发生变化,您将需要对项目进行排序。如果你这样实现,现在你需要实现一个排序。
包含的链接列表之所以存在,是因为它们已经过尝试、信任和调试。为这些编写自己的函数只是重复大量不必要的工作。
此外,您对额外对象节点的开销的担心实际上不应该太担心 - 额外的开销会是多少?在像今天这样的日子里,即使它们是千字节(这将是疯狂的),也不应该让人担心。
In general this is a recommended against because of the creep of features you will need in the future. Even if you don't need features like 'search' and 'sort' currently, someday the specs will change and you'll need to sort your items. If you implement it this way, now you need to implement a sort.
The included linked lists are there because they've been tried, trusted, and debugged. Writing your own function for these is just duplicating a lot of work that's not necessary.
In addition, your worry about having the overhead of an extra object node shouldn't really be too much of a worry - how much extra overhead could it be? In days like today even if they were a kilobyte (which would be crazy) it shouldn't add up to a worry.
我相信java中的XML DOM类会做你所描述的(类似的事情),所以至少有先例。一般来说,您所描述的可能是例外而不是规则,因为否则您最终只会重新实现链表。
I believe the XML DOM classes in java do (something like) what you describe, so there's at least precedent for it. Generally what you describe is probably the exception not the rule because otherwise you just end up re-implementing a linked list.
在 Java 中,与其他语言相比,这不是一个问题,因为
Item
必须是类指针。另一方面,如果Item
是一个结构(C# 和其他语言可能如此),那么您会遇到明显的问题。除了您拥有可变结构这一事实之外,您还可能会在尝试定义具有无限大内存需求的结构时遇到编译时错误。根据需求,允许对象通过 next 和 previous 引用它们的兄弟姐妹可能会更简单,层次结构中的对象通常可以通过引用它的父对象来引用它的父对象。
In Java, it's less of a problem than other languages, since the
Item
must be a class pointer. If, on the other hand,Item
is a struct, as is possible with C# and other languages, you run into obvious problems. Besides the fact that you've got a mutable struct, you'd also probably get a compile-time error trying to define a struct with an infinitely large memory requirement.Depending on requirements, it may be much simpler to allow objects to refer to their siblings through next and previous, the way an object in a hierarchy can often refer to it's parent by having a reference to it.
这种模式称为侵入性容器。
这并不是在每种情况下都正确的做法,但它具有一些众所周知的优点(更低的内存使用量、更好的局部性、内存管理器分配和收集的对象更少)。
This pattern is called an invasive container.
It's not the right thing to do in every situation, but it has some well-known advantages (lower memory usage, better locality, fewer objects for the memory manager to allocate and collect).
与往常一样,取决于您的项目范围和/或使用它的上下文。如果项目相当小,遵循每一个良好实践指南不会有太大帮助:您最终只会花费更多时间“正确”地完成它,而好处可能几乎为零。
如果您的项目有点大,但此链接列表仅在本地使用,例如在单个源文件中,或作为类的私有成员(换句话说,如果它是实现细节,而不是总体机制的一部分) ,那么您也可以跳过“正确”执行此操作并采用更简单的方法。
只有当项目很大并且链表是这个难题的重要组成部分时,您才应该花时间尽可能完美地完成它。根据经验,如果多个源文件需要此链表,请正确执行,不要偷工减料。
一般来说,知道何时以及如何花费你的精力。编写正确且健壮的代码与过度设计之间有一条非常微妙的界限。
As always, depends on the scope of your project and/or on the context in which this is used. If the project is rather small, following every single good-practice guideline won't be very helpful: you'll just end up spending more time doing it 'properly' and the benefits might be almost nil.
If your project is somewhat big, but this linked list is only used locally, like inside a single source file, or as a private member of a class (in other words, if it's an implementation detail, and not part of the overarching mechanism), then you can also skip doing it 'properly' and take the simpler approach.
Only when the project is large and the linked list is an important piece of the puzzle should you spend time doing it as flawlessly as you can. As a rule of thumb, if more than one source file needs this linked list, then do it properly, don't cut corners.
In general, know when and how to spend your energy. There's a very fine line to walk between writing correct and robust code and over-engineering.