The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Constructor Pattern

I'm wondering if anyone has a good idea or best practice about how to solve the following problem:

I have a hierarchy of classes.  Each layer in the hierarchy builds on the layer above it.  As part of this, the constructor for a given class passes some parameters up to the superclass and uses the remainder to configure its own local state.

Now, here's the problem.  I want some stuff to happen after all these parameters have been properly configured, or in other words after all the constructors have run.  But, I'd prefer not to have to put a line like

this.Initialize();

at the bottom of each constructor, where Initialize() is a private method defined on each class in the hierarchy.  Id' rather make it a standard part of the construction process that happens automatically, but I can't see any way to achieve this effect under the constraints of the construction process.

Not sure I'm explaining this very well, but I'm hoping there's an initialization pattern or something that I can use so I don't wind up hacking something together to achieve the effect I'm after.  Thanks in advance for any help.
fellow coder in need
Tuesday, July 19, 2005
 
 
In C++ this is handled by building a template that contains the stuff you want to happen at the "bottom" of your inheritance chain. Something like this:

class MyCoolStuff {
  ...
}

template< class T >
class MyStandardStuff : public T
{
  ...
}

Then, you actually do new MyStandardStuff< MyCoolStuff >() to actually create your object.

In languages without templates, not sure how you'd get around the Initialize method.
Chris Tavares Send private email
Tuesday, July 19, 2005
 
 
It is hard for me to imagine a time when you'd need to do this.

Either set up a pure virtual method called Initialise() in the base class and call this whenever you create an instance.  It is easy enough to ensure, programmatically, that Initialise() is called before you do anything else with the instance.

MyClass *myclass = new MyClass(arguments);
myclass->Initialise();

Or just write your constructors properly.  :)  It could be that I just don't know what problem you are trying to solve, though.  Can you come up with an example?
Chris in Edmonton Send private email
Tuesday, July 19, 2005
 
 
Base class constructors are called before the derived class constructors. Therefore, if you have base class code to call after derived class constructors, you can have a method called after construting the object or from every derived class constructor, use the template trick to drop the base stuff down to a lower level, or redesign the class.

I'm curious too: given how odd this is, what exactly are you trying to accompish? I'ld vote for redesigning your class, if at all possible, because as it stands you've either got a potential problem with forgetting to initialize some derived classes or specific instances, or an unusual syntax for creating a class that will confuse anyone using it, or trying to maintain the app 6 months after you move on to a better job. (Even if it's a hobby project, it would still be good to learn more maintanable techniques for when the problem pops up at your day job.)

Depending on what the class is doing, having an "if( !initialized) Initialize();" at the start of every base class method that requires the initialization to be done would mean that derived classes just work, and the initialization would be delayed until it's relevant. (The 'initialized' flag would be set to false in the base constructor, and set to true once Initialize() is called. The overhead of the extra test may or may not matter, but it's probably not your biggest problem.) Hey, it's another option, at least.

Tuesday, July 19, 2005
 
 
Thanks for the replies.  The problems mentioned in a few of the posts above are exactly why I've posted this question :)  I don't want them plaguing me.

Anyhow, without posting a ton of code, let me see if I can summarize what I'm trying to accomplish.  Essentially, what I have is a parser that recognizes different kinds of objects in its input stream.  Each of these objects is decorated with "stuff" so that when I create each kind of recognizable object, I pass this "stuff" into the constructor.  Some gets applied in the derived class and some propagates up to base classes.

Now, at the same time, there is a secondary source of information for these objects.  In order to access this secondary source, I have to make sure all the primary "stuff" is in place.  What I'd like to do is pull this secondary information into the system during object construction so that I don't have to have lazy-initialize code all over the place.  So, this means I want to call an Initialize() method after I'm certain all the primary "stuff" is in place.

Anyhow, I got tired of thinking about how to solve this problem through clever hackery.  Instead, I just decided to build a Factory that will create the objects and then make sure that each new instance loads its secondary information before the object is returned to the client.

I'd still be interested in hearing any clean approaches to the original problem, though.

BTW, I'm using C# on this one, just to narrow down the choices even further :P

Thanks again for taking the time to respond and for the interesting approaches.
fellow coder in need
Tuesday, July 19, 2005
 
 
Right up until you suggested it, I was going to suggest the factory design pattern.  :)

I suspect that your inheritance hierarchy needs rethinking.  The only reason I have to say this, though, is because I've never run into the problems you are describing and I've done some pretty intense class hierarchies and have used factory patterns before.  Your specific case may be different enough to warrant the hoops you are jumping through.  Also, my thinking is rather tuned to the C++ way these days, C# may be different in significant ways.

It may be worth your while looking through XML parsers for some inspiration.  Alternatively, you may want to consider a two-pass parser (though this should fill you with dread).

As someone else pointed out, in C++ at least, by the time your derived-constructor runs, all of the base constructors have already completed.  For this reason, it is normally sufficient to just stick this code in your constructor.  However, you seem to be wanting a two-pass initialisation rather than a bottom-up initialisation which is not so easy.  Either stick a call to Initialise() in the most-derived class's constructor or call it yourself.  Or try another idea.

Good luck.
Chris in Edmonton Send private email
Tuesday, July 19, 2005
 
 
I've had a similar problem in working with some existing classes I wasn't allowed to change enough, where you have a base class providing certain features, but at least one of the calls from the base constructor would be calling a virtual function (which just isn't allowed - the child class isn't built yet!)

In my case it was a matter of getting rid of the "work" the class was ment to do out from the "initialisation".  Use the constructor to initialise the class into a safe state, call functions after to do the work - even if you are going to do that work straight after construction every time.  It's cleaner in the end, though calling the 'extra function' seems annoying to start.

Tuesday, July 19, 2005
 
 
If Edsger W. Dijkstra would still be alive, I am sure he would write a paper about implementation inheritance. I am also quite certain that the words "considered" and "harmful" would have been part of the title (  http://www.acm.org/classics/oct95/ ).

I have now 12 years of oject oriented design behind me and as soon as I see the words AbstractXXX in classnames, I feel pain between my ears.

But there is medication! I have yet to see a class hierarchy which could not be made more simple, robust, maintainable by the use of aggregation. Instead of thinking along "isA" lines, try to see what using "hasA" can offer you.
icing Send private email
Wednesday, July 20, 2005
 
 
fellow coder,

I think you're on the right path, but I'd consider what your're implementing more of a Builder pattern. Sort of a factory that knows complicated rules about how objects are constructed.  Its in GOF...
Steve S
Wednesday, July 20, 2005
 
 
Thanks again for the input.  That factory that I implemented seems to have done the trick.  Normally, I'd like to keep that kind of stuff inside the object itself, but based on the responses, it seem like this is a reasonable tradeoff.

As far as the inheritance vs. aggregation/delegation thing, I think inheritance gets a bum rap for a few reasons.  First off, it's often abused (see the Liskov thread).  Also, I think that the avoidance of a robust model of multiple inheritance in a lot of languages really hamstrings the approach. For example, compare the inheritance system present in the Eiffel language with the one hosted in C#.  So, I guess my opinion is that when inheritance is *appropriate*, it is often the best solution.

As far as Factory vs. Builder, my understanding of Builder is that it is primarily used to transform some abstract or declarative description of some complex object structure into an instance of that structure.  It encapsulates a complicated algorithm for building complex structures.  It is the link between a declarative specification of a structure and an imperative specification of the structure.

The thing that I'm calling a factory doesn't seem to line up with this understanding of the Builder pattern.  It's not building a complicated structure because it emits individual object instances.  It doesn't seem to me to really be transforming a declarative specification, either.

The Factory, on the other hand, seems to be primarily responsible for generating well-formed instances, and for abstracting the implementation type from clients.  This factory I've made seems to qualify for the first part, and also for the second (the declarations are all in terms of interfaces).  So, this is why I've labeled it as a Factory...

Any other opinions?  Is my understanding of Builder flawed?
fellow coder in need
Wednesday, July 20, 2005
 
 
interface ObjectInterface {
    void init();
}

class AObject implements ObjectInterface {
  public AObject(Object param1) {...}
  public void init() {...}
}

class BObject extends AObject {
  public BObject(Object param1, Object param2) {
      super(param1);
      ...
  }

  public void init() {
      super.init();
      ...
  }
}

class ClassFactory {
  BaseObject createAObject(Class type, Object param) {
      BaseObject result = new AObject(param);
      if(result != null) result.init();
      return result;
  }

  BaseObject createBObject(Class type, Object param1, Object param2) {
      BaseObject result = new AObject(param1, param2);
      if(result != null) result.init();
      return result;
  }
}

You could also use static methods in each class AObject, or BObject to create an initialize your object instances.
Dino Send private email
Wednesday, July 20, 2005
 
 
Sorry about the Class type parameter. It shouldn't be part of the create methods signatures.

BaseObject createAObject(Object param)
BaseObject createBObject(Object param1, Object param2)
Dino Send private email
Wednesday, July 20, 2005
 
 
Someone just needs to write "all language features considered invariably and literally lethal to all life in the universe" and be done with the endless "feature X isn't completely beyond the possibility of abuse when used by an idiot" articles.

Wednesday, July 20, 2005
 
 
So to summarise something like?

class A { A(istream in) {...} virtual uint id(); };

class B: extends A { B(istream in):A(in) {...) uint id(); };

class C: extends B { C(istream in):B(in) {...} uint id(); };

A* AFactory(istream in) { switch(in.readuint()) { ... } };

But the bit that is interesting to me is the need for the second-phase construction.  What exactly is it that you want to do in the second-phase, and why can't it be done in the first?

Handling a failure in the second phase and cleaning up correctly can be tricky.

Bjarne Stroustrup had something to say about this (C++ obviously, but in principle widely applicable).  I just can't find a link to his bit..

He was discussing how constructing things in a constructor list before the body of the constructor itself gave automatic guarentees about rollback on failure.
new nick, new rep
Thursday, July 21, 2005
 
 
"But the bit that is interesting to me is the need for the second-phase construction.  What exactly is it that you want to do in the second-phase, and why can't it be done in the first?"

Probably the best way to explain it, without getting into too much detail, is that a set of "key" values are passed into the constructor.  At each level of construction, the constructor passes some of the keys up to the superclass constructor and uses the remaining values to initialize its locally defined state.  The main thing is that all the keys have to be in place for me to be able to take the next step.

The best way to conceptualize the next step is that the class uses all of the key values to query a secondary storage mechanism to pull in some related information about the newly constructed object.  Until all the keys are in place, though, this query can't be properly formulated.

There are lots of solutions to this problem, many of which have been kindly pointed out and discussed above.  I could have used lazy initialization to pull this secondary information in upon first access.  I could have put a call to an Initialize() method into each constructor, etc. 

I guess what I was wanting to do was to make the root constructor behave like a template method of sorts, so that I could keep all the construction logic in the constructor, but at the same time avoid forcing subclasses to be aware of the need to call that Initialize() method at each level. 

Clearly, I could have taken the pragmatic approach and just done it, but I'm sure some of you know how it is when "it just seems like there should be a better way." It bugs ya :)

What I eventually settled on was a factory that would call the constructor on the correct class and then call the Initialize() method to be sure that everything was correct when the call to the factory returned.  This has worked well and has the added bonus of decoupling the client code from the implementation types being used (though this is not really important for the current application).

So, anyhow, thanks again to everyone who responded :) Hope I can return the favor some day.
fellow coder in need
Thursday, July 21, 2005
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz