0

I am finding a recurring pattern in my day-to-day coding, as follows:

var foo = new Foo();
foo.Initialize(params);
foo.DoSomething();

In these cases, foo.Initialize is absolutely needed so that it can actually DoSomething, otherwise some foo properties would still be null/non-initialized.

Is there a pattern to it? How to be safely sure DoSomething will only/always be called after Initialize? And how to proceed if it doesn't: should I raise an exception, silent ignore it, check some flag...?

heltonbiker
  • 26,657
  • 28
  • 137
  • 252
  • 3
    Can the initialization logic be performed in the constructor? It seems silly to have a separate method for the purpose of finishing construction of the object. – David Jan 12 '16 at 16:15
  • @David I've read a handful of things about "No real work in constructor", "no `new` in constructor", and these got me a bit reluctant to do everything that must be done. Alternatives seem to be to relax the contract of the class (it wouldn't be ready to work at all times), but don't know how this relaxing should/would be done... – heltonbiker Jan 12 '16 at 16:40
  • 2
    "No `new` in constructor" is really more an issue of dependency management than of "too much work". You need to understand *why* certain things are not recommended and what issues they entail, then choose your own solution best fit for your situation. Dogma is the worst decision maker. – deceze Jan 12 '16 at 16:52

2 Answers2

5

Essentially you're saying Initialize is a constructor. So that code really should be part of the constructor:

var foo = new Foo(params);
foo.DoSomething();

That's exactly what a constructor is for: it's code which is guaranteed to run before any of the object methods are run, and its job is to check pre-conditions and provide a sane environment for other object methods to run.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • Except it's a better practice to create an `.Init(...)` method if the required work is heavy. – Matthew Whited Jan 12 '16 at 16:18
  • 1
    If the *required* work is absolutely ***required*** before any of the other methods can be run, there's really no difference whether it's in some other method or not. It *has* to run before you can do anything else with the object. If your constructor is so heavy, some general refactoring may be in order. Perhaps you really want a factory instead. – deceze Jan 12 '16 at 16:20
  • I would assume that is work against that object. Think of something like user controls and forms. You want them instantiated quickly but they have an entire setup process before they can render stuff. – Matthew Whited Jan 12 '16 at 16:23
  • You could also do lazy init where the .Init() function is called internally the first time the object is used. – Matthew Whited Jan 12 '16 at 16:25
  • I'm not saying you are wrong but their are times that the `.Init(...)` pattern makes sense. – Matthew Whited Jan 12 '16 at 16:26
  • That's why I feel between a rock and a hard place... I always felt @decese is right - no point in having an "unsafe to use" object, but then the "no real work in constructor" kicks in and I feel a bit hesitant... – heltonbiker Jan 12 '16 at 16:30
  • For example, see the debate here: http://stackoverflow.com/questions/5764689/is-it-violation-of-clean-code-to-call-init-method-in-constructor-like-this – heltonbiker Jan 12 '16 at 16:33
  • "No real work in constructor" is a totally misguided and horrible idea. Just forget you ever heard about it. – n. m. could be an AI Jan 12 '16 at 16:48
  • @heltonbiker Again, perhaps you're actually looking for a factory, which does all the heavy lifting and just returns a "light" object which merely represents the work done/the new state/provides a handle to the instantiates components. – deceze Jan 12 '16 at 16:49
  • 1
    The constructor must leave the object in a usable state. It's an absolute, undisputable requirement. If this requires real work, then this constructor must do real work. – n. m. could be an AI Jan 12 '16 at 16:55
  • 1
    @n.m.: Which begs the question... "usable" by *whom*? A private constructor can leave an object in a state that is perfectly usable by a factory method, which in turn is responsible for returning the object in a usable state to whomever invoked that method. Multi-stage initialization processes aren't uncommon. A good example would be the ASP.NET WebForms page life cycle. – David Jan 12 '16 at 16:57
  • @n.m.: In that case the OP's code is perfectly acceptable inside of a factory method. Since the constructor would be private, *only* the class itself may use it. So the object still internally encapsulates all of its initialization logic. – David Jan 12 '16 at 17:04
  • 2
    There's nothing wrong per se with having an initialisation function! See e.g. fstream::open. You cannot use a stream which was not opened. Throw an exception someone tries to use your object before initialisation. It is a logic error and should be treated as such. Now when you have your separate ctor and init function, write an overloaded ctor that does both things (just like one in fstream). – n. m. could be an AI Jan 12 '16 at 17:08
  • @David I think it's OK to treat a factory as a big constructor – n. m. could be an AI Jan 12 '16 at 17:09
  • @n.m. that's a fair point about `fstream::open`. That's the kind of "contract doesn't guarantees class will always be ready" thing I was considering... – heltonbiker Jan 12 '16 at 17:34
2

If there really is a lot of work taking place in the initialization, then I can certainly see the argument that it's "too much to put in a constructor". (I'm sure somebody with a deeper familiarity of language mechanics under the hood could provide some compelling explanations on the matter, but I'm not that person.)

It sounds to me like a factory would be useful here. Something like this:

public class Foo
{
    private Foo()
    {
        // trivial initialization operations
    }

    private void Initialize(SomeType params)
    {
        // non-trivial initialization operations
    }

    public static Foo CreateNew(SomeType params)
    {
        var result = new Foo();
        result.Initialize(params);
        return result;
    }
}

And the consuming code becomes:

var foo = Foo.CreateNew(params);
foo.DoSomething();

All manner of additional logic could be put into that factory, including a variety of sanity checks of the params or validating that heavy initialization operations completed successfully (such as if they rely on external resources). It would be a good place to inject dependencies as well.

This basically comes down to a matter of cleanly separating concerns. The constructor's job is to create an instance of the object, the initializer's job is to get the complex object ready for intended use, and the factory's job is to coordinate these efforts and only return ready-for-use objects (handling any errors accordingly).

David
  • 208,112
  • 36
  • 198
  • 279
  • That's quite interesting. And what should be done in case something goes wrong in `CreateNew`? – heltonbiker Jan 12 '16 at 17:00
  • @heltonbiker: You can put whatever error handling you like in `CreateNew`. It's no different than handling exceptions or error conditions anywhere else in your code. – David Jan 12 '16 at 17:02