Philosophical question: Template Method

D

Dave Rahardja

OK, so I've gotten into a philosophical disagreement with my colleague at
work. He is a proponent of the Template Method pattern, i.e.:

class foo
{
public:
void bar() { do_bar(); }
protected:
virtual void do_bar() {}
};

class baz: public foo
{
protected:
virtual void do_bar() {} // overridden
};

As you can see, the non-virtual public method foo:bar() exists only to invoke
the virtual method do_bar, which derivatives of the class can override like a
regular virtual method.

The advantage to this method, my colleague claims, is that future implementors
may change the pre- and post-processing behavior of the virtual do_bar method
(such as adding semaphore acquisition/relinquishment calls before/after the
call to do_bar, respectively) without changing the classes that derive from
foo.

Furthermore, he claims that this separates the decision to make a method
public/private from the decision to make a method virtual--a significant
advantage, he claims.

He has pointed me to articles on C++ Users Journal which seems to support the
Template Method pattern, even going so far as to say that all public virtual
methods should be banned in favor of the Template Method.

See http://www.cuj.com/documents/s=8000/cujcexp1812hyslop/

I, on the other hand, prefer the simple

class foo
{
public:
virtual void bar() {}
};

class baz: public foo
{
public:
virtual void bar() {} // overridden
};

And being a big fan of Java, I also appreciate the Interface pattern:

class foo // interface
{
public:
virtual void bar() = 0;
};

class baz: virtual public foo
{
public:
virtual void bar() {} // implementation
};

Besides, the Template Method can be ruined if a derived class decides that it
needs a different pre- and post-operation for the virtual method...

class foo
{
public:
void bar() { do_bar(); }
protected:
virtual void bar() {}
};

class baz: public foo
{
public:
void bar() { frobnicate(); do_bar(); } // I need something different!
proctected:
virtual void bar() {} // overridden
};

In the above class hierarchy, the two calls...

baz baz_object;
foo& foo_reference(baz_object);
baz& baz_reference(baz_object);

foo.bar();
baz.bar();

....would yield two different call paths.

Of course you can say "don't do that", but I can also say "but I need to
override the default behavior for this class".

So what say you, gentle coders? Are Template Methods worth the hassle? Do they
trade one class of errors for another? Is the convenience of changing pre- and
post-operations at the base class actually masking the fact that we have made
a design error and honestly need to re-examine every descendant class?

The Template Method pattern is not compatible with the Interface method, not
because it can't be done, but because it makes no sense to combine them. Empty
non-virtual public methods whose jobs it is is to simply call pure virtual
protected methods--that's just silly.

So it's one or the other, then. What's the better design paradigm?
 
D

David White

Dave Rahardja said:
OK, so I've gotten into a philosophical disagreement with my colleague at
work. He is a proponent of the Template Method pattern, i.e.:

class foo
{
public:
void bar() { do_bar(); }
protected:
virtual void do_bar() {}
};

class baz: public foo
{
protected:
virtual void do_bar() {} // overridden
};

As you can see, the non-virtual public method foo:bar() exists only to invoke
the virtual method do_bar, which derivatives of the class can override like a
regular virtual method.

I use this for large hierarchies, though I didn't know it had a name (I do
have Design Patterns; guess I'll have to refresh my memory).
The advantage to this method, my colleague claims, is that future implementors
may change the pre- and post-processing behavior of the virtual do_bar method
(such as adding semaphore acquisition/relinquishment calls before/after the
call to do_bar, respectively) without changing the classes that derive from
foo.

Yes, that's one reason.

Another is that without it your public interface is cluttered up with the
same functions in every derived class. I like to keep the smallest public
interface possible. If a member is public in the base class it doesn't need
to be public anywhere else. So I use it even if I can't imagine ever wanting
to do more than call the protected virtual from the public non-virtual.

Another reason is that you can add a breakpoint or some debugging code to
the public function; all calls have to go through there.

I have classes in which I use this pattern for all these reasons.
Furthermore, he claims that this separates the decision to make a method
public/private from the decision to make a method virtual--a significant
advantage, he claims.

I don't see much in that reason. I wouldn't have a function's virtualness
influencing its access rights (in those smaller hierarchies where I don't
bother with this method).
He has pointed me to articles on C++ Users Journal which seems to support the
Template Method pattern, even going so far as to say that all public virtual
methods should be banned in favor of the Template Method.

No need to ban it. As much as I like the Template Method, I don't think
public virtuals are actually evil.
See http://www.cuj.com/documents/s=8000/cujcexp1812hyslop/

I, on the other hand, prefer the simple

class foo
{
public:
virtual void bar() {}
};

class baz: public foo
{
public:
virtual void bar() {} // overridden
};

And being a big fan of Java, I also appreciate the Interface pattern:

class foo // interface
{
public:
virtual void bar() = 0;
};

class baz: virtual public foo
{
public:
virtual void bar() {} // implementation
};

Besides, the Template Method can be ruined if a derived class decides that it
needs a different pre- and post-operation for the virtual method...

class foo
{
public:
void bar() { do_bar(); }
protected:
virtual void bar() {}

Don't you mean: virtual void do_bar() {}?
};

class baz: public foo
{
public:
void bar() { frobnicate(); do_bar(); } // I need something different!

If this is what's suitable for the class. Are you sure that this function
should be called bar() though? Maybe a different name would be more
suitable. If it should be bar() then I'd suggest making it virtual as well
(and protected everywhere, and add a new public function Bar() to the base
class that calls bar(); i.e., a double template method!).
proctected:
virtual void bar() {} // overridden

virtual void do_bar() {} again?
};

In the above class hierarchy, the two calls...

baz baz_object;
foo& foo_reference(baz_object);
baz& baz_reference(baz_object);

foo.bar();
baz.bar();

...would yield two different call paths.

Yes, that's why I don't like it.
Of course you can say "don't do that", but I can also say "but I need to
override the default behavior for this class".

You haven't explained how _not_ using the template method solves your
problem.
So what say you, gentle coders? Are Template Methods worth the hassle?

For large hierarchies with a large number of what would have been public
virtual functions, I think so.
Do they
trade one class of errors for another?

No, what do you gain by not using it, apart from having to write one less
function? The public non-virtual can be inline, so there isn't even a
performance cost.
Is the convenience of changing pre- and
post-operations at the base class actually masking the fact that we have made
a design error and honestly need to re-examine every descendant class?

You can't possibly generalize about that. It depends on the particular
circumstances. I see nothing inherently wrong with having pre- and post-
operations, if that's the reason for using the method.
The Template Method pattern is not compatible with the Interface method,

I'll have to look that one up as well.
not
because it can't be done, but because it makes no sense to combine them. Empty
non-virtual public methods whose jobs it is is to simply call pure virtual
protected methods--that's just silly.

That's exactly what I do, and I have a nice small public interface
throughout the hierarchy with no performance cost.
So it's one or the other, then. What's the better design paradigm?

Both.

DW
 
D

David White

tom_usenet said:
Surely:

class baz: public foo
{
proctected:
virtual void do_bar() {
frobnicate();
//more stuff
}
};

Except that if this class is derived from, this do_bar() might not be called
first.

DW
 
D

Dave Rahardja

I suppose this is one of those messages that prove that you shouldn't write a
philosophical message when you've been testing code all day ;-)

Don't you mean: virtual void do_bar() {}?
Yes.


virtual void do_bar() {} again?

Yes again.

Another is that without it your public interface is cluttered up with the
same functions in every derived class. I like to keep the smallest public
interface possible. If a member is public in the base class it doesn't need
to be public anywhere else. So I use it even if I can't imagine ever wanting
to do more than call the protected virtual from the public non-virtual.

I'm afraid I don't see how the Template Method pattern reduces the clutter in
the public interface: you have one public non-virtual method for every
protected virtual method. As is the case with public non-virtual base class
methods, you only override public virtual base class methods when you need to:

class dee
{
public:
virtual void dum() {}
};

class duh
{
public:
// Use base class implementation of dum()
};

The class duh doesn't have any additional clutter in its public interface than
if we were to use the Template Method.

Yes, that's why I don't like it.

Another mistake; those calls should read

foo_reference.bar();
baz_reference.bar();

What I was trying to illustrate was that the author of baz was trying to
preempt what foo::bar() (not foo::do_bar()) was doing by redefining the bar()
method. Maybe foo::bar() manipulated a semaphore, but the author of baz did
not want to do that. Additionally, she also wanted all derived classes of baz
to use the baz::bar() method instead of foo::bar().

No, what do you gain by not using it, apart from having to write one less
function? The public non-virtual can be inline, so there isn't even a
performance cost.

Although those extra methods tend to be very short, inlined methods, they do
add up to additional code, which increases the potential of errors, but that's
not the kind of errors I'm most concerned about.

The errors that are most insidious take place when an author tries to fix a
problem in an algorithm used by a large number of derived classes by fixing
the public non-virtual base class method. Even if the fix appears to work, he
still needs to examine and re-test all of the derived classes to ensure that
he hasn't broken anything.

Here's an example:

class foo
{
public:
void dee() { pre_dee(); do_dee(); post_dee(); }
void dum() { pre_dum(); do_dum(); post_dum(); }
protected:
virtual void do_dee() {}
virtual void do_dum() {}
};

class bar: public foo
{
proctected:
virtual void do_dee() { dum(); frobnicate(); } // note call to dum()
};

We can assume that bar::do_dee() calls foo::dum() because the former method
needs the pre- and post-code found in foo:dum().

The author then discovers that he needs to serialize access to the foo
hierarchy by protecting its public methods with a mutual exclusion object, so
he changes the foo methods to read:

class foo
{
public:
void dee() { acquire(); pre_dee(); do_dee(); post_dee(); relinquish() }
void dum() { acquire(); pre_dum(); do_dum(); post_dum(); relinquish() }
protected:
virtual void do_dee() {}
virtual void do_dum() {}
};

But note that he has now broken bar::do_dee(), because acquire() will now be
called twice in a row, possibly resulting in deadlock.

I guess we can impose the constraint that derived classes only call the
protected do_xxx methods instead of their public non-virtual counterparts.
However, the usefulness of gathering common pre- and post-codes in the publc
non-virtual base class methods is lost.


And for our final illustration on why a tired brain cannot express ideas in a
Usenet message without introducing errors I give you...
I'll have to look that one up as well.

That paragraph should read:

The Template Method pattern is not compatible with the Interface method, not
because it can't be done, but because it makes no sense to combine them. Empty
non-virtual public methods whose jobs it is is to simply call pure virtual
PUBLIC methods--that's just silly.

Nice.
 
D

Dave Rahardja

Yes, I've seen similar articles, and the streambuf heirarchy in the
standard library is a practical example of this technique. The methods
sputn, pubsetbuf, pubseekoff, etc. are simple inline forwarders to
protected virtual functions. In this case the aim appears to have been
consistency - made all the virtual functions protected, since some of
them have to be.

Yes, and my colleague has pointed out other places in the standard library
where this pattern is used. What I'm trying to understand is why the pattern
is used. Does it offer any advantage in the long run?

I think you have to ask your friend how many times he's actually added
pre and post code to a template method that he couldn't have
anticipated right from the start. I suspect rarely, in which case
there wasn't really much point in using a template method at all, it
just made the code a bit less clear.

That is also an argument that I have made. I think I can only think of two or
three occasions in the last five years where I have had to change a method
found in more than two related classes because I forgot to write some pre- or
post-code.

OTOH, making all virtual methods private or protected is a simple rule
to learn that can't really hurt and might well help from time to time.
However, sometimes the "interface" idiom is flexible in that it allows
you to replace wholesale an implementation, without retaining any code
at all. This becomes difficult if you require virtual methods to be
private/protected.

The Interface pattern has saved my skin many times over. I have written many
device drivers in the past two years, and for a handful of different embedded
platforms. Coding the applications against an pure abstract device interface
has allowed me to swap entire device drivers from under the codebase without
changing the application code.
 
D

David White

Dave Rahardja said:
I'm afraid I don't see how the Template Method pattern reduces the clutter in
the public interface: you have one public non-virtual method for every
protected virtual method. As is the case with public non-virtual base class
methods, you only override public virtual base class methods when you need to:

class dee
{
public:
virtual void dum() {}
};

class duh
{
public:
// Use base class implementation of dum()
};

The class duh doesn't have any additional clutter in its public interface than
if we were to use the Template Method.

Of course, because you haven't overridden it. Why have a virtual function if
you _never_ override it? Consider a draw() function in a hierarchy of
graphical objects. Every derived class overrides it, so you keep seeing
draw() in the public interface of every class you look at, as well as every
other virtual that is normally overridden. I'd rather have have one
non-virtual Draw() in the base class that calls the protected virtual
draw().
Another mistake; those calls should read

foo_reference.bar();
baz_reference.bar();

What I was trying to illustrate was that the author of baz was trying to
preempt what foo::bar() (not foo::do_bar()) was doing by redefining the bar()
method. Maybe foo::bar() manipulated a semaphore, but the author of baz did
not want to do that. Additionally, she also wanted all derived classes of baz
to use the baz::bar() method instead of foo::bar().

Yes, I understand that. I don't like the same object behaving differently
when the same function is called, according only to the static type of its
declaration. That's why I don't regard it as an acceptable solution.
Although those extra methods tend to be very short, inlined methods, they do
add up to additional code, which increases the potential of errors, but that's
not the kind of errors I'm most concerned about.

Additional source code, but only a small amount. The potential for error is
an insignificant consideration IMO.
The errors that are most insidious take place when an author tries to fix a
problem in an algorithm used by a large number of derived classes by fixing
the public non-virtual base class method. Even if the fix appears to work, he
still needs to examine and re-test all of the derived classes to ensure that
he hasn't broken anything.

Here's an example:

class foo
{
public:
void dee() { pre_dee(); do_dee(); post_dee(); }
void dum() { pre_dum(); do_dum(); post_dum(); }
protected:
virtual void do_dee() {}
virtual void do_dum() {}
};

class bar: public foo
{
proctected:
virtual void do_dee() { dum(); frobnicate(); } // note call to dum()
};

We can assume that bar::do_dee() calls foo::dum() because the former method
needs the pre- and post-code found in foo:dum().

The author then discovers that he needs to serialize access to the foo
hierarchy by protecting its public methods with a mutual exclusion object, so
he changes the foo methods to read:

class foo
{
public:
void dee() { acquire(); pre_dee(); do_dee(); post_dee(); relinquish() }
void dum() { acquire(); pre_dum(); do_dum(); post_dum(); relinquish() }
protected:
virtual void do_dee() {}
virtual void do_dum() {}
};

But note that he has now broken bar::do_dee(), because acquire() will now be
called twice in a row, possibly resulting in deadlock.

I guess we can impose the constraint that derived classes only call the
protected do_xxx methods instead of their public non-virtual counterparts.
However, the usefulness of gathering common pre- and post-codes in the publc
non-virtual base class methods is lost.

I don't see this as much of an argument. You can break anything if you don't
know what you're doing.

How would you do this if you did not use the Template Method?

DW
 
D

Dave Rahardja

Of course, because you haven't overridden it. Why have a virtual function if
you _never_ override it? Consider a draw() function in a hierarchy of
graphical objects. Every derived class overrides it, so you keep seeing
draw() in the public interface of every class you look at, as well as every
other virtual that is normally overridden. I'd rather have have one
non-virtual Draw() in the base class that calls the protected virtual
draw().

I don't see anything wrong with declaring overrides in the public parts of
derived classes. I understand that you have a penchant for keeping the public
parts of classes to a minimum.

In other words, it's

class duh: public dee
{
public:
// overrides of dee
virtual void dum() {}
};

versus

class duh: public dee
{
protected:
virtual void do_dum() {}
};

What's the big deal?

Yes, I understand that. I don't like the same object behaving differently
when the same function is called, according only to the static type of its
declaration. That's why I don't regard it as an acceptable solution.
Right.


I don't see this as much of an argument. You can break anything if you don't
know what you're doing.

How would you do this if you did not use the Template Method?

I would change each virtual method in every derived class so that they work
properly. Is this error-prone? Sure. Is it more error-prone that simply
modifying the base class non-virtual method? I don't know. I think the two
approaches yield two different classes of errors in this case.


What I'm gathering from the discussion in this thread is that there is no
clearly superior pattern here--just two different patterns. I can see how the
Template Method can solve a certain class of problems (it is especially useful
for algorithms that need to call a sequence of virtual methods in a specific
order); while the Interface pattern, although somewhat incompatible, solves a
different kind of problem: that of replacing concrete implementations
wholesale without affecting the users of the interface.

I'm coming away from this believing that Template Methods should be used only
when necessary--and that the general case does not necessitate it. Your desire
to minimize the public interface aside (I, for one, do not have that desire; I
only want to make clear which public methods are new in a derived class and
which are overrides), requiring Template Methods for all virtual methods is
unnecessary at best and tedious at worst. Even worse, insisting that all
virtual methods should be protected (as the CUJ article did) borders on the
impractical.

I feel that I'm going to have to struggle with this question for a little
longer. I have built a moderately large class library based on the Interface
paradigm with outstanding success, but that's because the problem domain I
work in (device drivers) lends itself well to this pattern. Perhaps another
domain will benefit from Template Methods.

I have much to learn yet! ;)
 
D

David White

Dave Rahardja said:
I don't see anything wrong with declaring overrides in the public parts of
derived classes. I understand that you have a penchant for keeping the public
parts of classes to a minimum.

In other words, it's

class duh: public dee
{
public:
// overrides of dee
virtual void dum() {}
};

versus

class duh: public dee
{
protected:
virtual void do_dum() {}
};

What's the big deal?

It's not such a big deal. It's just a preference. On occasions I might
override a dozen virtuals but only add two or three genuinely new functions.
I'd rather see a public interface of three functions than fifteen.

Also, it really isn't the client's business which derived classes override a
certain function and which don't. All the client has to know is that it can
call Draw() on any object. This is most accurately expressed by having a
single public Draw() in the base class.
I would change each virtual method in every derived class so that they work
properly. Is this error-prone? Sure. Is it more error-prone that simply
modifying the base class non-virtual method? I don't know. I think the two
approaches yield two different classes of errors in this case.

If it is necessary to do the same thing exactly once before anything else
(say, acquire()) no matter which override is invoked first, how would ensure
that that's what happens if you don't use the Template Method? Remember
that, for a given class, it might or might not be appropriate for an
override to call the inherited implementation of the function, or it might
be appropriate to call it first in some cases and last in others. So how
_do_ you ensure that acquire() is called first, and only once, no matter
what?
What I'm gathering from the discussion in this thread is that there is no
clearly superior pattern here--just two different patterns. I can see how the
Template Method can solve a certain class of problems (it is especially useful
for algorithms that need to call a sequence of virtual methods in a specific
order); while the Interface pattern, although somewhat incompatible, solves a
different kind of problem: that of replacing concrete implementations
wholesale without affecting the users of the interface.

I'm coming away from this believing that Template Methods should be used only
when necessary--and that the general case does not necessitate it. Your desire
to minimize the public interface aside (I, for one, do not have that desire; I
only want to make clear which public methods are new in a derived class and
which are overrides), requiring Template Methods for all virtual methods is
unnecessary at best and tedious at worst. Even worse, insisting that all
virtual methods should be protected (as the CUJ article did) borders on the
impractical.

I feel that I'm going to have to struggle with this question for a little
longer. I have built a moderately large class library based on the Interface
paradigm with outstanding success, but that's because the problem domain I
work in (device drivers) lends itself well to this pattern. Perhaps another
domain will benefit from Template Methods.

I have much to learn yet! ;)

The Template Method is used to solve a problem, e.g., ensuring that things
are done in the right order. If you don't use the Template Method, but you
still have to do things in the right order, then you have to do it some
other way. This pattern is just one of many programming techniques that
solve certain problems, so you use it where it works if it seems to be a
good solution.

DW
 
T

tom_usenet

What I'm gathering from the discussion in this thread is that there is no
clearly superior pattern here--just two different patterns. I can see how the
Template Method can solve a certain class of problems (it is especially useful
for algorithms that need to call a sequence of virtual methods in a specific
order); while the Interface pattern, although somewhat incompatible, solves a
different kind of problem: that of replacing concrete implementations
wholesale without affecting the users of the interface.

I'm coming away from this believing that Template Methods should be used only
when necessary--and that the general case does not necessitate it. Your desire
to minimize the public interface aside (I, for one, do not have that desire; I
only want to make clear which public methods are new in a derived class and
which are overrides), requiring Template Methods for all virtual methods is
unnecessary at best and tedious at worst. Even worse, insisting that all
virtual methods should be protected (as the CUJ article did) borders on the
impractical.

I feel that I'm going to have to struggle with this question for a little
longer. I have built a moderately large class library based on the Interface
paradigm with outstanding success, but that's because the problem domain I
work in (device drivers) lends itself well to this pattern. Perhaps another
domain will benefit from Template Methods.

Note that the two techniques aren't entirely mutually exclusive:

class MyInterface
{
public:
virtual void f() = 0;
virtual void g() = 0;
};

class MyAbstractBase: public MyInterface
{
public:
void f()
{
do_f();
}
void g()
{
//add other code here?
do_g();
}

protected:
virtual void do_f() = 0;
virtual void do_g() = 0;
};

etc.

Now, users can derive from MyAbstractBase if they want any common
algorithmic code, or they can replace the implementation wholesale.

Finally, there is a third technique - composition - that always tends
to be more powerful than inheritence alone:

class MyInterface
{
public:
virtual void f() = 0;
virtual void g() = 0;
};

class MyClass
{
public:
void f()
{
ptr->f();
}

void g()
{
//other implementation?
ptr->g();
}

private:
MyInterface* ptr;
};

Here, you can even make MyClass::f and g virtual, if you really want,
but I think that defeats the point. MyClass optionally has runtime
switchable behaviour.

Tom
 
D

Dave Rahardja

If it is necessary to do the same thing exactly once before anything else
(say, acquire()) no matter which override is invoked first, how would ensure
that that's what happens if you don't use the Template Method? Remember
that, for a given class, it might or might not be appropriate for an
override to call the inherited implementation of the function, or it might
be appropriate to call it first in some cases and last in others. So how
_do_ you ensure that acquire() is called first, and only once, no matter
what?

That would be one case where I would use the Template Method.

My colleague is espousing that we use the Template Method in _anticipation_ of
a class of errors that can be fixed by augmenting the base class non-virtual
method. I think such an attitude is overkill; the Template Method is not
appropriate everywhere.

The Template Method is used to solve a problem, e.g., ensuring that things
are done in the right order. If you don't use the Template Method, but you
still have to do things in the right order, then you have to do it some
other way. This pattern is just one of many programming techniques that
solve certain problems, so you use it where it works if it seems to be a
good solution.

Right!
 
R

Risto Lankinen

David White said:
It doesn't
tell you that it's overriding a base-class function.

Omission of "virtual" in the overriding declaration
doesn't tell that either.

- Risto -
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top