Philosophical question: Template Method

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Dave Rahardja

    Philosophical question: Template Method

    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(b az_object);
    baz& baz_reference(b az_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?

  • David White

    #2
    Re: Philosophical question: Template Method

    "Dave Rahardja" <ask@me.com> wrote in message
    news:2r11jvsdvt 6pf8klucocbjbv4 cnmve2foi@4ax.c om...[color=blue]
    > 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[/color]
    invoke[color=blue]
    > the virtual method do_bar, which derivatives of the class can override[/color]
    like a[color=blue]
    > regular virtual method.[/color]

    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).
    [color=blue]
    > The advantage to this method, my colleague claims, is that future[/color]
    implementors[color=blue]
    > may change the pre- and post-processing behavior of the virtual do_bar[/color]
    method[color=blue]
    > (such as adding semaphore acquisition/relinquishment calls before/after[/color]
    the[color=blue]
    > call to do_bar, respectively) without changing the classes that derive[/color]
    from[color=blue]
    > foo.[/color]

    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.
    [color=blue]
    > 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.[/color]

    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).
    [color=blue]
    > He has pointed me to articles on C++ Users Journal which seems to support[/color]
    the[color=blue]
    > Template Method pattern, even going so far as to say that all public[/color]
    virtual[color=blue]
    > methods should be banned in favor of the Template Method.[/color]

    No need to ban it. As much as I like the Template Method, I don't think
    public virtuals are actually evil.
    [color=blue]
    > 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[/color]
    it[color=blue]
    > needs a different pre- and post-operation for the virtual method...
    >
    > class foo
    > {
    > public:
    > void bar() { do_bar(); }
    > protected:
    > virtual void bar() {}[/color]

    Don't you mean: virtual void do_bar() {}?
    [color=blue]
    > };
    >
    > class baz: public foo
    > {
    > public:
    > void bar() { frobnicate(); do_bar(); } // I need something different![/color]

    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!).
    [color=blue]
    > proctected:
    > virtual void bar() {} // overridden[/color]

    virtual void do_bar() {} again?
    [color=blue]
    > };
    >
    > In the above class hierarchy, the two calls...
    >
    > baz baz_object;
    > foo& foo_reference(b az_object);
    > baz& baz_reference(b az_object);
    >
    > foo.bar();
    > baz.bar();
    >
    > ...would yield two different call paths.[/color]

    Yes, that's why I don't like it.
    [color=blue]
    > 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".[/color]

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

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

    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.
    [color=blue]
    > Is the convenience of changing pre- and
    > post-operations at the base class actually masking the fact that we have[/color]
    made[color=blue]
    > a design error and honestly need to re-examine every descendant class?[/color]

    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.
    [color=blue]
    > The Template Method pattern is not compatible with the Interface method,[/color]

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

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

    Both.

    DW



    Comment

    • David White

      #3
      Re: Philosophical question: Template Method

      "tom_usenet " <tom_usenet@hot mail.com> wrote in message
      news:3f30d2d8.1 79845812@news.e asynet.co.uk...[color=blue]
      > On Tue, 05 Aug 2003 23:58:39 -0500, Dave Rahardja <ask@me.com> wrote:[color=green]
      > >class baz: public foo
      > >{
      > >public:
      > > void bar() { frobnicate(); do_bar(); } // I need something different!
      > >proctected:
      > > virtual void bar() {} // overridden
      > >};[/color]
      >
      > Surely:
      >
      > class baz: public foo
      > {
      > proctected:
      > virtual void do_bar() {
      > frobnicate();
      > //more stuff
      > }
      > };[/color]

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

      DW



      Comment

      • Dave Rahardja

        #4
        Re: Philosophical question: Template Method

        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 ;-)

        [color=blue][color=green]
        >> class foo
        >> {
        >> public:
        >> void bar() { do_bar(); }
        >> protected:
        >> virtual void bar() {}[/color]
        >
        >Don't you mean: virtual void do_bar() {}?[/color]

        Yes.
        [color=blue][color=green]
        >> proctected:
        >> virtual void bar() {} // overridden[/color]
        >
        >virtual void do_bar() {} again?[/color]

        Yes again.

        [color=blue]
        >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.[/color]

        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.

        [color=blue][color=green]
        >> In the above class hierarchy, the two calls...
        >>
        >> baz baz_object;
        >> foo& foo_reference(b az_object);
        >> baz& baz_reference(b az_object);
        >>
        >> foo.bar();
        >> baz.bar();
        >>
        >> ...would yield two different call paths.[/color]
        >
        >Yes, that's why I don't like it.[/color]

        Another mistake; those calls should read

        foo_reference.b ar();
        baz_reference.b ar();

        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().

        [color=blue][color=green]
        >> Do they
        >> trade one class of errors for another?[/color]
        >
        >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.[/color]

        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...
        [color=blue][color=green]
        >> The Template Method pattern is not compatible with the Interface method,[/color]
        >
        >I'll have to look that one up as well.
        >[color=green]
        >> not
        >> because it can't be done, but because it makes no sense to combine them.[/color]
        >Empty[color=green]
        >> non-virtual public methods whose jobs it is is to simply call pure virtual
        >> protected methods--that's just silly.[/color][/color]

        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.
        [color=blue][color=green]
        >> So it's one or the other, then. What's the better design paradigm?[/color]
        >
        >Both.[/color]

        Nice.

        Comment

        • Dave Rahardja

          #5
          Re: Philosophical question: Template Method

          On Wed, 06 Aug 2003 10:25:55 GMT, tom_usenet@hotm ail.com (tom_usenet) wrote:
          [color=blue]
          >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.[/color]

          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?

          [color=blue]
          >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.[/color]

          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.

          [color=blue]
          >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.[/color]

          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.

          Comment

          • David White

            #6
            Re: Philosophical question: Template Method

            Dave Rahardja <ask@me.com> wrote in message
            news:0402jvg8lb 2qnffs8o58nbu2a hi169910e@4ax.c om...[color=blue][color=green]
            > >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[/color][/color]
            need[color=blue][color=green]
            > >to be public anywhere else. So I use it even if I can't imagine ever[/color][/color]
            wanting[color=blue][color=green]
            > >to do more than call the protected virtual from the public non-virtual.[/color]
            >
            > I'm afraid I don't see how the Template Method pattern reduces the clutter[/color]
            in[color=blue]
            > the public interface: you have one public non-virtual method for every
            > protected virtual method. As is the case with public non-virtual base[/color]
            class[color=blue]
            > methods, you only override public virtual base class methods when you need[/color]
            to:[color=blue]
            >
            > 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[/color]
            than[color=blue]
            > if we were to use the Template Method.[/color]

            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().
            [color=blue][color=green][color=darkred]
            > >> In the above class hierarchy, the two calls...
            > >>
            > >> baz baz_object;
            > >> foo& foo_reference(b az_object);
            > >> baz& baz_reference(b az_object);
            > >>
            > >> foo.bar();
            > >> baz.bar();
            > >>
            > >> ...would yield two different call paths.[/color]
            > >
            > >Yes, that's why I don't like it.[/color]
            >
            > Another mistake; those calls should read
            >
            > foo_reference.b ar();
            > baz_reference.b ar();
            >
            > 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[/color]
            bar()[color=blue]
            > method. Maybe foo::bar() manipulated a semaphore, but the author of baz[/color]
            did[color=blue]
            > not want to do that. Additionally, she also wanted all derived classes of[/color]
            baz[color=blue]
            > to use the baz::bar() method instead of foo::bar().[/color]

            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.
            [color=blue]
            >[color=green][color=darkred]
            > >> Do they
            > >> trade one class of errors for another?[/color]
            > >
            > >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.[/color]
            >
            > Although those extra methods tend to be very short, inlined methods, they[/color]
            do[color=blue]
            > add up to additional code, which increases the potential of errors, but[/color]
            that's[color=blue]
            > not the kind of errors I'm most concerned about.[/color]

            Additional source code, but only a small amount. The potential for error is
            an insignificant consideration IMO.
            [color=blue]
            > The errors that are most insidious take place when an author tries to fix[/color]
            a[color=blue]
            > problem in an algorithm used by a large number of derived classes by[/color]
            fixing[color=blue]
            > the public non-virtual base class method. Even if the fix appears to work,[/color]
            he[color=blue]
            > still needs to examine and re-test all of the derived classes to ensure[/color]
            that[color=blue]
            > 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[/color]
            method[color=blue]
            > 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,[/color]
            so[color=blue]
            > 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[/color]
            be[color=blue]
            > 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[/color]
            publc[color=blue]
            > non-virtual base class methods is lost.[/color]

            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



            Comment

            • Dave Rahardja

              #7
              Re: Philosophical question: Template Method

              On Thu, 7 Aug 2003 09:00:12 +1000, "David White" <no@email.provi ded> wrote:
              [color=blue][color=green]
              >> 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[/color]
              >than[color=green]
              >> if we were to use the Template Method.[/color]
              >
              >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().[/color]

              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?

              [color=blue][color=green][color=darkred]
              >> >> In the above class hierarchy, the two calls...
              >> >>
              >> >> baz baz_object;
              >> >> foo& foo_reference(b az_object);
              >> >> baz& baz_reference(b az_object);
              >> >>
              >> >> foo.bar();
              >> >> baz.bar();
              >> >>
              >> >> ...would yield two different call paths.
              >> >
              >> >Yes, that's why I don't like it.[/color]
              >>
              >> Another mistake; those calls should read
              >>
              >> foo_reference.b ar();
              >> baz_reference.b ar();
              >>
              >> 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[/color]
              >bar()[color=green]
              >> method. Maybe foo::bar() manipulated a semaphore, but the author of baz[/color]
              >did[color=green]
              >> not want to do that. Additionally, she also wanted all derived classes of[/color]
              >baz[color=green]
              >> to use the baz::bar() method instead of foo::bar().[/color]
              >
              >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.[/color]

              Right.

              [color=blue]
              >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?[/color]

              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! ;)

              Comment

              • David White

                #8
                Re: Philosophical question: Template Method

                Dave Rahardja <ask@me.com> wrote in message
                news:00f3jvke3f 92uqqkp96ib35gd dp2apq3j3@4ax.c om...[color=blue]
                > On Thu, 7 Aug 2003 09:00:12 +1000, "David White" <no@email.provi ded>[/color]
                wrote:[color=blue]
                >
                > 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[/color]
                public[color=blue]
                > 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?[/color]

                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.
                [color=blue][color=green]
                > >How would you do this if you did not use the Template Method?[/color][/color]
                [color=blue]
                > I would change each virtual method in every derived class so that they[/color]
                work[color=blue]
                > 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.[/color]

                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?
                [color=blue]
                >
                > 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[/color]
                the[color=blue]
                > Template Method can solve a certain class of problems (it is especially[/color]
                useful[color=blue]
                > for algorithms that need to call a sequence of virtual methods in a[/color]
                specific[color=blue]
                > order); while the Interface pattern, although somewhat incompatible,[/color]
                solves a[color=blue]
                > 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[/color]
                only[color=blue]
                > when necessary--and that the general case does not necessitate it. Your[/color]
                desire[color=blue]
                > to minimize the public interface aside (I, for one, do not have that[/color]
                desire; I[color=blue]
                > only want to make clear which public methods are new in a derived class[/color]
                and[color=blue]
                > which are overrides), requiring Template Methods for all virtual methods[/color]
                is[color=blue]
                > unnecessary at best and tedious at worst. Even worse, insisting that all
                > virtual methods should be protected (as the CUJ article did) borders on[/color]
                the[color=blue]
                > 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[/color]
                Interface[color=blue]
                > paradigm with outstanding success, but that's because the problem domain I
                > work in (device drivers) lends itself well to this pattern. Perhaps[/color]
                another[color=blue]
                > domain will benefit from Template Methods.
                >
                > I have much to learn yet! ;)[/color]

                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



                Comment

                • tom_usenet

                  #9
                  Re: Philosophical question: Template Method

                  On Wed, 06 Aug 2003 21:56:03 -0500, Dave Rahardja <ask@me.com> wrote:
                  [color=blue]
                  >
                  >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.[/color]

                  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

                  Comment

                  • Dave Rahardja

                    #10
                    Re: Philosophical question: Template Method

                    On Thu, 7 Aug 2003 15:18:06 +1000, "David White" <no@email.provi ded> wrote:
                    [color=blue]
                    >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?[/color]

                    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.

                    [color=blue]
                    >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.[/color]

                    Right!

                    Comment

                    • David White

                      #11
                      Re: Philosophical question: Template Method


                      "David White" <no.email@provi ded> wrote in message
                      news:E1qYa.441$ d6.39879@nasal. pacific.net.au. ..[color=blue]
                      > Although, all that tells you is that it's virtual in that class.[/color]

                      ....and any derived classes of course.

                      DW



                      Comment

                      • Risto Lankinen

                        #12
                        Re: Philosophical question: Template Method


                        "David White" <no.email@provi ded> wrote in message
                        news:E1qYa.441$ d6.39879@nasal. pacific.net.au. ..[color=blue]
                        > "Risto Lankinen" <rlankine@hotma il.com> wrote in message
                        > news:ubpYa.9204 $g4.179105@news 1.nokia.com...[color=green]
                        > >
                        > > Some consider
                        > > it good style to label the overriding function virtual as
                        > > well, though.[/color]
                        >
                        > It doesn't
                        > tell you that it's overriding a base-class function.[/color]

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

                        - Risto -



                        Comment

                        Working...