We all know the difference between a Constructor
and a User-Defined Initialize()
method fundamentally.
My question is focused on best design practice for object creation. We can put all Initialize()
code into Constructor()
and vice versa (move all warm-up code to Initialize
method and call this method from Constructor
).
Currently, designing a new class, I create any new instances inside constructor()
and move any other warm-up code into Initialize()
method.
What's the best trade-off point in your opinion?
A class object with a constructor must be explicitly initialized or have a default constructor. Except for aggregate initialization, explicit initialization using a constructor is the only way to initialize non-static constant and reference class members.
Object Initializers were something added to C# 3, in order to simplify construction of objects when you're using an object. Constructors run, given 0 or more parameters, and are used to create and initialize an object before the calling method gets the handle to the created object.
A copy constructor is a member function that initializes an object using another object of the same class.
Simply speaking, a constructor does not create an object. It just initializes the state of the object. It's the new operator which creates the object.
I think there are multiple aspects that should be taken into consideration:
A constructor should initialize an object in a way that it's in a usable state.
A constructor should only initialize an object, not perform heavy work.
A constructor should not directly or indirectly call virtual members or external code.
So in most cases an Initialize method shouldn't be required.
In cases where initialization involves more than putting the object into a usable state (e.g., when heavy work needs to be performed or virtual members or external need to be called), then an Initialize method is a good idea.
I've found myself thinking about this a fair bit recently (hence finding this question) and whilst I dont have an answer I thought I'd share my thoughts.
this.member = member;
In my opinion this plays nicely with IoC, inheritance, testing and just smells nice.
However heavy lifting is sometimes required so what I've been trying to do is:
That means abstracting that initialisation code to another class and passing that in. This is usually possibly if the heavy lifting is not really your objects responsibility, so doing this actually refactors to nicer code.
If this is not possible and you do need to initialise state for your class before usage then add an initialse method. This does add temporal dependency into your code but this is not necessarily a bad thing especially when using IoC containers:
Say CarEngine
requires a DrivingAssistComputer
, and the DrivingAssistComputer
needs to do heavy initialisation, i.e. Load all parameters, weather condition checks, etc. Another thing to note is that CarEngine
does not directly interact with the DrivingAssistComputer
, it just needs it to be present, doing its own thing on the side. In fact the engine may not work properly without the DrivingAssistComputer
doing its thing in the background (changing some state somewhere). If we are using IoC then we have:
// Without initialise (i.e. initialisation done in computer constructor)
public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) {
this.injectors = injectors;
// No need to reference computer as we dont really interact with it.
}
...
So what we have here is a constructor argument marking computer
as a dependancy but not actually using it. So this is ugly, but lets add an Initialise method:
public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) {
this.injectors = injectors;
// This ofcourse could also be moved to CarEngine.Initialse
computer.Initialise();
}
...
Still not a cohesive class but at least we know that we depend on computer even though we are not directly interacting with it outside of the constructor.
Another option ofcourse is to have a CarEngineFactory that does:
CarEngine CreateEngine(FuelInjectors injectors) {
new DrivingAssistComputer().Initialise();
return new CarEngine(injectors);
}
...
However, I find factories and IoC just confuse the matrix so I would go for the second option.
Would love to hear some thoughts on this.
Edit 1: Another option I missed above is having the Initialise method but moving this invocation to the IoC initialisation module. So creation and initialisation are still somewhat encapsulated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With