I'm fairly new to the OO design process, so please bear with me....
I have two entities that I need to model as classes, call them Parent and Child (it's close enough to the actual problem domain). One Parent will have one or more Children -- I have not interest, in this application, in childless Parents.
Where my brain is going out to lunch is on the fact that I need to be able to find either from the other. In my database I can implement this with a normal foreign key relationship, and the set-based nature of SQL makes it easy to find all Children for a given Parent, or the Parent for a given Child. But as objects...?
I think that the Parent should carry a collection (list, whatever) of Children. I also think that each Child should carry a reference to its Parent. The circular nature of the references, however, is making my head hurt.
Am I:
On the right track?
Completely off base? If so, what should I do differently?
This will almost certainly be implemented in VB.NET, but I'm a ways from cutting code yet.
Edit after 8 answers:
Thanks all. It was hard to pick just one answer to accept.
To clarify a couple of things that were questioned in the answers:
Parent and Child are very different
entities--there's not inheritance
relationship at all. I chose the
names that I did because they're
really very close to the real-world
problem domain, and now see that it's
a source of confusion from an OO
perspective.
The hierarchy is only one level deep--Children will never have Children
within the application.
Thanks again.
The circular references are fine and absolutely standard when creating a tree structure. HTML's Document Object Model (DOM), for example, has the parent and child properties on every node in a DOM tree:
interface Node {
// ...
readonly attribute Node parentNode;
readonly attribute NodeList childNodes;
// ...
}
Sounds like you're on the right track to me. As per your domain model, parents have children and children have parents. You may need to reference each from the other.
There is nothing wrong with circular references, you just have to be careful about what you do with them. Where you'll run into trouble is managing your entities on the server side in an automated fashion when you load them from the database. For example, you fetch a Child object from the database with a query. Do you include the parent information? Do you include the parent's children?
ORM tools like Lightspeed or Microsoft's Entity Framework generally deal with this using "lazy loading" directives. They'll fetch what you need at first (so, when you fetch a Child, it just gets the Child properties and the parent's ID). If later, you dereference the Parent, it goes and fetches the Parent properties and instantiates the Parent object. If later still, you access it's Children collection, it then goes and fetches the relevant child information and creates Child objects for that collection. Until you need them though, it doesn't populate it.
I think it's reasonable to want to be able to traverse the object graph in this way. It's hard to know if you have a justifiable reason for it from your post, but I don't think the references in and of themselves prove a bad design.
I believe you're on the right track. Why is the circular nature of the references making your head hurt? What is the fundamental issue you're having with a Parent having references to its children, and a Child having a reference to its parent?
Are you talking about a class hierarchy, where the parent class knows about its child classes?
You should avoid this at all costs.
By default, a child class knows all about a parent class, because it is an instance of the parent class. But to have a parent class know about its child classes requires that the child class also know all about every other child class. This creates a dependency between one child and every other child of that class. This is an unmaintainable scenario that will cause problems in the future -- if you can even get it to compile or run, which in many languages will not be the case.
That said, it sounds to me like you're not trying to do a class hierarchy, but a collection hierarchy, i.e. a tree. In that case, yes, you're on the right track; it's a common paradigm. The parent node has a collection of child nodes, and the child node has a reference to the parent node.
The thing is? They're all the same class! Here's a very simple example in C#:
public class Node
{
public readonly Node Parent; // null Parent indicates root node
public readonly List<Node> Children = new List<Node>();
public Node(Node parent)
{
Parent = parent;
}
public Node()
{
parent = null;
}
public void AddChild(Node node)
{
Children.Add(node);
}
}
I have a feeling this is what you're really after. Using this paradigm, you would then sub-class Node for whatever nefarious purposes you might have.
If I understand that objects of P contain an array of objects P->c[] representing children. And any node P with no children is a leaf ... with each P containing P->P' (the parent).
The solution you specify, with Parents containing references to children and vice versa eliminates the need to traverse the tree to obtain ancestry of a given child and children of a node. This is really just a tree that can you perform all kinds of links on and algorithms to traverse and enumerate it. Which is fine!
I suggest reading the trees chapter in The Art of Computer Programming for an excellent and in-depth look at tree structures and efficient ways to enumerate parentage and children.
If the children must have a parent I usually just require a parent type instance in the child constructor.
Sounds to me like you're on the path to a bad design. Your architecture should never have circular references.
You should probably re-examine why your children need a reference back to the parent and vice versa. I would lean toward the parent having a collection of children. You can then add functionality to the parent to check to see if a child object is a child of the instance.
A better explination of the goal might be a little more helpful as well...
EDIT
I read up a little more (and listened to comments)...and it turns out I'm quite in the wrong. Circular references do in fact have their place as long as you're careful with them and don't let them get out of hand.
Related
I am new to Golang. I have this example here - https://go.dev/play/p/lusSZk5be4b
I am trying to update the global parent structure from one of the elements of the same parent structure. I was expecting this program might create an issue because of updating the parent structure from it's own child but this seems to work fine.
I did not understand if this is the right behaviour and is accepted in golang or this kind of updating the parent from child should not be done at all. Any help is appreciated.
Thank you.
You're not actually replacing the parent, but the global variable.
If you keep a reference to the original parent you'll see things remain the same there:
https://go.dev/play/p/FsNVdheZPfE
func main() {
p = &parent{}
oldParent = p
...
fmt.Pritnln(oldParent)
...
Even if you had an actual parent on the child struct and update it (example: https://go.dev/play/p/hELKFB7DWc- ) , the original reference would still have the child, but the child would have a parent with no children.
So in summary, you're just updating references which is totally valid. Whether that makes sense in code or you might lose an important reference that's a different thing.
I've read this spring-data-rest tutorial https://spring.io/guides/gs/accessing-data-rest/ and I can't see how this can be applied in a real world situation where we don't have just one object, but a graph of objects.
Let's say that we have an Order object which has one-to-many relationship to an Item which is categorized by a Category object. Let's say for the sake of it, that the Category is implemented in a tree-like structure (so it has a parent and some children; i.e. an Electronic category could have 2 children, Computer and TV, the former having another two children, motherboard and keyboards).
And let's say that all these relation are two ways (i.e. an Order can see it's items and an Item can access it's Order)
So when I request an Order object threw my REST service, I'm gone get the Order, all it's Items and each Item will have the whole graph of Category which will be linked to each Item and thus all the orders. So I'm basically returning the whole database.
I do understand that the bidirectional relations is not ideal but even if we suppress the many side of the relationship, when requesting an Order, we would still get
Order-Item-Category-Parent Category-Parent of Parent Category-etc...
So how do you stop a graph of objects being serialized?
Furthermore, you might not want to break the graph at a fix point.
For instance when I request an Order, I might want to see it's items and the category of each item, but definitely not the parent's category.
However, when I want to explicitly display a Category, I would then like to see it's parent. Get it?
Does somebody have some insight for me?
This is where DTOs are a good thing. :)
You build the object structure you need and return it via json. You have full control over this structure, you dont have bidirectional relations and you can just give that back as an object graph from your controller.
Another (good) side effect is that you decouple persistence and view completely. I.e both can evolve independently.
One (negative) side effect can be the increased maintenance. You have, at least, twice the classes to maintain and also the mapping in between. Frameworks like Dozer can help you with the mapping at least.
Another solution can be to implement some addons for Jackson that handle all these cases without the need of DTOs.
I myself created the Antpath filter to dynamically decide which path to filter out in Jackson:
https://github.com/Antibrumm/jackson-antpathfilter
But you will need some more things to consider if you like to work with domain entities directly.
cycle breaker (to avoid bidirectional relations for example)
lazy loading / open session in view pattern as the serialization can go everywhere
hibernate proxies which have method which are not serializable (session)
Suppose I have the following nested UI-Router route:
/parent/{parentId}/child/{childId}
parent:child in my case is a one:many relation, therefore any valid childId implies a specific parentId. I'd like to maintain the nested state in my application, keeping access to parent resolve dependencies without reloading between sibling children; but instead represent the above with the terser URL:
/child/{childId}
Ideally, I'd like UI-Router to do as much of the lifting as possible, and only write the action to recover just the parent state when it is lost (for example when loading the entire page from a child route URL).
My responsibility could, for instance, be simply handling recovery of the parentId state parameter when it is null.
Is this feasible?
edits day 2: It seems, according to the docs, that UI-Router is designed to allow obscuring parent routes from the URL using Absolute Routes. I can only assume that it is supposed to preserve the parent state normally in this case. So, I tried a quick implementation by including two identical URLs, one an absolute URL that is a child state of the parent, and the other that is an actual root state, which does nothing but resolve the parent parameter, then load a controller to perform a redirect to the actual parent/child route. It had lots of problems. I'm trying to determine if I can do the same thing with an abstract state above the parent route. Anyway, suffice to say I haven't solved this yet.
The problem I am trying to solve is to prevent circular references not just between an immediate parent and child, but I also want to ensure that a new child is not already used as a parent somewhere in the hierarchy of records.
I thought I might solve the problem by intercepting the assignment of a parent before executing the code,
self.parent = maybe_the_wrong_choice
and then do important validation before saving the change.
Am I on the right path? If so, how do I grab the old value of an attribute in my Model validation (e.g. self.old_parent) and compare it with the new parent (self.parent) before saving the record?
Thanks in anticipation!
You can get the old parent by self.parent_was and new parent by self.parent.
I am creating a document based project using Core Data and have run into what may simply be a conceptual issue for me, as while I am not new to Cocoa, this is my first attempt to utilize Core Data. What I am trying to accomplish should be relatively simple: with each new document launched, I would like a new instance of one of my model objects created that serves as a "root" object.
What I have done is add an NSObjectController to my xib, set its mode to Entity Name (with the correct entity name provided), checked off "Prepares Content", and bound its managed object context to File's Owner with managedObjectContext as the model key path. To test this, I bound the title of my main window to the object controller, with controller key as selection and model key path as one of the keys in my entity.
I know I can create my root object programmatically, but am trying to adopt the mediator pattern as is recommended by Apple. I have seen the instructions in the department-employee tutorial under the "adopting the mediator pattern" section and the steps detailed are exactly what I believe I have done.
Any thoughts?
Edit:
Perhaps I did not state the problem correctly. The models are created in Core Data and the relationships are setup as I need them to be (with a "root", children and leaves, using to-one parent relationships, to-many children relationships and an isLeaf boolean attribute). My issue is ensuring that this root object is instantiated as a singleton every time a new document is launched. There should be exactly a 1:1 relationship between the root object and the current document, that root object must always exist and be available without any user interaction to create it, and child nodes that are created and attached to the root are the data objects that are used and manipulated by the application.
I have implemented the above functionality programatically, but in keeping with Core Data principles, would like to adopt the mediator pattern completely and not manage any creation of data objects within my application logic.
If you want a "root" managed object like you would find in linked-list or tree, then you have to set that up in data model itself.
By default, a Core Data data model has no particular hierarchy among objects. Objects may be related but no object is logically "above" or "below" another one. You can reach in object in any relationship by starting with any other object and walking the relationship/s back to the desired object.
A hierarchy of managed objects needs a tree like structure like this:
Tree{
nodeName:string
parent<-->>Tree.children
children<<-->Tree.parent
}
... so that the "root" object is the sole Tree instances that has parent==nil.
Having said all this, I would point out that the Apple docs you refer to say that it is best NOT to use this type of built in hierarchy for most cases. It's just a simplification used for purposes of demonstration (and I think it is a bad one.)
The data model is intended to model/simulate the real-world objects, conditions or events that the app deals with. As such, the logical relationships between the entities/objects in the model/graph should reflect the real-world relationships. In this case, unless the real-world things you are modeling exist in a hierarchy with a real-world "root" object, condition or event, then your model shouldn't have one either.