1

Which of the following two models makes more sense? I'm leaning towards the first one because there can only be one default child.

The examples are in C# but I think it can apply to other languages too.

Here DefaultChild holds one of the items in Children.

class Parent
{
    int ID { get; set; }

    Child DefaultChild { get; set; }

    IEnumerable<Child> Children { get; set; }
}

class Child
{
    int ID { get; set; }
}

Here one of the items in Children has Default set to true while the others have it set to false.

class Parent
{
    int ID { get; set; }

    IEnumerable<Child> Children { get; set; }
}

class Child
{
    int ID { get; set; }

    bool Default { get; set; }
}

A concrete situation: a User in our system has one or more Customers attached. When logging in, if said User has a default Customer, they are immediately working under this Customer. If they don't, they have to select a Customer to work under. While logged in, they can switch between Customers.

9
  • Neither. Why would a parent instance be created that doesn't have a child? Then it wouldn't be a parent. I can't recall ever having a need to do what you are asking. Maybe more context would be helpful.
    – Dunk
    Jun 2, 2014 at 14:45
  • Who is interested in the default child? Do you need access to this information from outside either class? Do you need to know whether a given child is default, when you have no reference to the parent?
    – CodeCaster
    Jun 2, 2014 at 14:46
  • @Dunk I've added my actual situation to the question.
    – Stijn
    Jun 2, 2014 at 14:51
  • To use Microsoft terminology, DefaultChild is really just an MRU (most-recently-used) default?
    – Brian
    Jun 2, 2014 at 14:53
  • 1
    Ooops, by default you meant operator selected default and not a Default Child instance. Anyways, going with the concrete situation it seems pretty obvious that method #1 is the only one that will work. Option 2 breaks if Parent1 has child1 as its default and Parent2 has child2 as its default but also child1 as a customer.
    – Dunk
    Jun 2, 2014 at 17:41

2 Answers 2

6

In your specific scenario, a Parent should have a DefaultChild. The problem with giving a child an IsDefault property is that it A) allows for Parents with multiple default children and B) disallows Parents of the same child to have different settings for their child. The fact that neither of these scenarios can actually happen is irrelevant; both scenarios logically make sense, despite not at all matching your intentions.

From a high level perspective, it makes more sense to talk about the Default child of a parent than to say a particular child is inherently a default.

3

You are confusing contract details with implementation details. A contract is the API that objects expose to be manipulated.

What you need to decide upon is what interface you need for those objects. How those objects are implemented is just an exercise in code efficiency.

Let's assume the following interfaces make sense.

public interface iNode
{
     int getID();
     bool isDefault();
}

public interface iParent : iNode
{
     iNode getDefault();
     IEnumerable<iNode> getChildren();
}

What methods your interface has can limit or expand your implementation details. You need to decide if you need isDefault knowledge of an iNode in your code elsewhere.

Here is one approach.

public class Node : iNode
{
    public int getID() { return _id; }
    public bool isDefault() { return _default; }
}

public class Parent : Node
{
    public iNode getDefault() { return getChildren().FirstOrDefault(child=>child.isDefault()); }
    public IEnumerable<iNode> getChildren() { return _children; }
}

Alternatively, if you do not require that iNode expose that it is a default.

public class Node : iNode
{
    public int getID() { return _id; }
}

public class Parent : Node
{
    public iNode getDefault() { return _default; }
    public IEnumerable<iNode> getChildren() { return _children; }
}

It's important to focus on how your objects will be used, and not get overly distracted by how they will be implemented. Do you expect to have references to iNode objects and no longer have a reference to it's parent? If so, maybe it should have a flag that it's the default.

Still, you could just add getParent to the iNode interface.

I think you need to flush out your object contracts first.

1
  • Ah, interesting way to look at it. I (currently) don't expect to have an iNode in a context without its iParent, so the second approach fits the current situation.
    – Stijn
    Jun 2, 2014 at 15:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.