How to design a class to prevent circular dependencies from calling derived members before construction?
c#, circular-dependency, inheritance, java, oop
Solution
Personally, I don't like circular references. But if you decide to leave them, you may add some laziness:
interface IKernel
{
// Useful members, e.g. AvailableMemory, TotalMemory, etc.
}
class Kernel : IKernel
{
private readonly Lazy<FileManager> fileManager; // Every kernel has 1 file manager
public Kernel() { this.fileManager = new Lazy<FileManager>(() => new FileManager(this)); /* etc. */ }
// implements the interface; members are overridable
}
class FileManager
{
private /*readonly*/ IKernel kernel; // Every file manager belongs to 1 kernel
public FileManager(IKernel kernel) { this.kernel = kernel; /* etc. */ }
}
Laziness here lets ensure, that IKernel implementation will be initialized completely, when FileManager instance will be queried.
Problem
(I tagged this as both C# and Java, since it's the same question in both languages.) Say I have these classes ``` interface IKernel { // Useful members, e.g. AvailableMemory, TotalMemory, etc. } class Kernel : IKernel { private /*readonly*/ FileManager fileManager; // Every kernel has 1 file manager public Kernel() { this.fileManager = new FileManager(this); /* etc. */ } // implements the interface; members are overridable } class FileManager { private /*readonly*/ IKernel kernel; // Every file manager belongs to 1 kernel public FileManager(IKernel kernel) { this.kernel = kernel; /* etc. */ } } ``` The problem with this design is that as soon as `FileManager` tries to do anything inside its constructor with `kernel` (which it might reasonably need to), it will be calling a virtual method on a potential subclass instance whose constructor is not yet called. This problem doesn't occur in languages where you can define true constructors (rather than initializers, like C#/Java), since then the subclasses don't even exist before their constructors are called... but here, this problem happens. So what is the best/proper design/practice, to ensure this doesn't happen? Edit: I'm not necessarily saying I need circular references, but the fact is that both `Kernel` and `FileManager` depend on each other. If you have a suggestion on how to alleviate this problem without using circular references, then that's great too!