0

The Situation:

I have three classes: Society, Father and Son. The Society has a list of Fathers. Each Father has one son. It is necessary in this application that each Father knows who his Son is and vice-versa each Son knows who his Father is.

I have used direct cross referencing by assigning the Father as a property of the Son, and the Son as a property of the Father class, as below:

public class Society : ISociety
{
    public List<IFather> Fathers {get; set;}
}


public class Father : IFather
{
    public Father(ISon inp_son)
    {
       MySon = inp_son; 
    }

    public ISon MySon {get; set;} 
}


public class Son : ISon
{
    public Son(IFather inp_father)
    {
       MyFather = inp_father;  
    }

    public IFather MyFather {get; set;}
}

To manually implement dependency inversion, I have a public static class called Factory. The Factory returns interfaces of the Society, Father and Son classes through its methods. The methods instantiate Society, Father and Son classes and return them respectively as ISociety, IFather and Ison.

public static Factory
{
    public static IFather CreateFather()
    {
        return new Father(CreateSon());
    }


    public static ISon CreateSon()
    {
        return new Son(CreateFather());
    }
}

The application runs as follows.

.
.
.
     IFather Father = Factory.CreateFather();
     Society.Fathers.Add(Father);      
.
.
.

The proeblem:

Every time the factory creates a Father, it instantiates a Son as its constructor input by invoking the CreateSon() method. When the CreateSon() method creates a Son, it invokes the CreateFather() method. This causes an endless loop, resulting in the StackOverFlow problem.

The big picture:

I have a large class library. In my library, higher-level classes have lists of lower-level classes. Calculations are performed inside the lower-level classes. The calculations need to access the properties of the higher-level classes. Therefore, the calculations need to somehow find their way to the higher level classes through the low-level class they belong to.

To be able to unit-test the code, I need to instantiate the Son class by passing the Factory.CreateFather() in to the constructor of the Son.cs class. Doing so allows me to swap out the Father class with say Mother class in the Factory class without breaking the code.

I don't know of a more elegant way to allow the Son to know who the Father is other than these two ways:

1- The above-mentioned approach, which is cross referencing by directly assigning the MyFather property of the son.

2- Saving an identifier property of the Father (int number or Guid) in the Son. So the son can search for the Father by: Father MyFather = Society.Fathers[MyFathersNumber]. Given the list of Fathers is controlled not to have duplicates. The problem with this approach is that in a long chain of hierarchy, accessing a class several layers up becomes a difficult navigation and a lengthy line of code.

I had previously moved from way-2 to way-1 as a cleaner approach in the absence of dependency inversion. Now I am having StackOverFlow problem when I combine way-2 with the DI principle.

My Question:

Can someone please tell me what is the elegant way to let the Son know who his father is without causing a conflict with the Dependency Inversion Principle?

Thank you.

Mechanician
  • 13
  • 1
  • 5
  • Is this the actual problem you're having? Modelling fathers and their sons? Or is this a rewrite from the actual problem? The reason I'm asking is that tips you might get about fathers and sons might not be applicable to something completely different, and vice versa. – Lasse V. Karlsen May 14 '20 at 10:12
  • 1
    As an indication of the kind of issue I have with your modelling is that constructing a father when you construct a son is rather strange, as conceptually the father must already exist when the son comes into existance. They don't appear in the universe together, so modelling them as such is odd. Instead you should try to think of how to model the fact that you already have the father in the universe and then the son comes into existance and must be linked to him. For instance, making the father the factory object and manually assigning a Father property on the Son once constructed. – Lasse V. Karlsen May 14 '20 at 10:15
  • No this is not the actual code. It is just the re-creation of the situation in a simplified form. The actual class library is much larger. – Mechanician May 14 '20 at 10:15
  • 1
    If we leave fathers and sons out of it, you have 2 services that depend on each other, why are they not the same service then? – Lasse V. Karlsen May 14 '20 at 10:15
  • Because of the relationship between the two objects in the real-world, they cannot be the same object. The higher level object (father) has other properties. These properties and their data belong to the father and need not be copied every time a new instance of a lower-level object (son) is created by the algorithm (talking about hundreds of iterations in an optimization algorithm). Each lower-level object needs to have access to all the other properties in the higher-level object to perform its calculations. – Mechanician May 14 '20 at 10:22
  • But the way you've modelled this each father can have 1 son and each son can have 1 father, there's no "every time a new instance of a lower-level object is created". It's going to happen 1 time. Once. This is why you should focus on your *actual* problem. Your make-believe simplified problem has problems of its own, and it's impossible for us to separate the problems you want solved from the problems you created by trying to simplify it, because we don't know what the actual model is. – Lasse V. Karlsen May 14 '20 at 10:26
  • The main problem you have with the code in the question is that you allow sons to be created without knowledge of their father which thus auto-creates a father. As I indicated above, this is an entirely wrong model because the real world doesn't work like that. However, if your actual code has a similar issue, don't let it be possible to create sons without passing in the father, and make the father involved in the factory, or let the father *be* the factory, and pass in the father to the son, instead of creating one. – Lasse V. Karlsen May 14 '20 at 10:28
  • ie. `public Son CreateSon() => new Son(this);` would solve your entire problem. – Lasse V. Karlsen May 14 '20 at 10:28
  • To be able to unit-test the code, I would like to instantiate the Son class by passing the `Factory.CreateFather()' in to the constructor of the Son class. This allows me to swap out the Father.cs class with, say, Mother.cs class without breaking my code. Please take a look at [this](https://www.youtube.com/watch?v=NnZZMkwI6KI) explanation, which shows what I am trying to achieve by the Factory class. – Mechanician May 14 '20 at 11:05

0 Answers0