How to implement Template method pattern

1,209 views
Skip to first unread message

Googol Lee

unread,
Nov 19, 2010, 3:45:43 AM11/19/10
to golang-nuts
Hi,

I just try to port some code to golang. And the original code use
Template method pattern for some different behavior classes. Like:

class Node:
def do_some_work(self):
#...
self.prepare()
#...
self.run()
#...

class Command(Node):
def prepare(self):
# do some prepare
def run(self):
# do the work

class Spawner(Node):
def prepare(self):
# spawn self to some more nodes

def run(self):
# collect some information from spawned nodes

Because there is no inherited, I find it's hard to port these code to
golang without big switch/case. I think it should be I miss some
feature of the language. Is there any way to do it beautiful?

Thanks.

chris dollin

unread,
Nov 19, 2010, 3:54:11 AM11/19/10
to Googol Lee, golang-nuts
On 19 November 2010 08:45, Googol Lee <goog...@gmail.com> wrote:

See the recent thread:

GO type embedding questions

(sorry, don't know how to link to it off-hand).

The essence is that you give the object corresponding to the
base class in your example one or more function pointers
to the "overridable methods" you'd use in a template method.
Or you pass in an object (of a class) satisfying an interface
which has the methods you want.

Chris

--
Chris "allusive" Dollin

jimmy frasche

unread,
Nov 19, 2010, 4:00:56 AM11/19/10
to chris dollin, Googol Lee, golang-nuts
> (sorry, don't know how to link to it off-hand).

You look it up or search for it on the google groups page,
http://groups.google.com/group/golang-nuts/topics

type embedding thread:
http://groups.google.com/group/golang-nuts/browse_thread/thread/a2f5868f6d364063#

To answer the question you define an interface with prepare and run
methods and then define a struct that embeds that interface and has
all the other methods that use prepare and run, then you create
instances of that struct with a Command or Spawner as the embeddee.

Googol Lee

unread,
Nov 19, 2010, 4:11:26 AM11/19/10
to golang-nuts
Got it. Thank you.

It seems need pass Node instance to the interface if prepare/run
function need access it.

On Nov 19, 5:00 pm, jimmy frasche <soapboxcic...@gmail.com> wrote:
> > (sorry, don't know how to link to it off-hand).
>
> You look it up or search for it on the google groups page,http://groups.google.com/group/golang-nuts/topics
>
> type embedding thread:http://groups.google.com/group/golang-nuts/browse_thread/thread/a2f58...

jimmy frasche

unread,
Nov 19, 2010, 4:18:51 AM11/19/10
to Googol Lee, golang-nuts
On Fri, Nov 19, 2010 at 1:11 AM, Googol Lee <goog...@gmail.com> wrote:
> It seems need pass Node instance to the interface if prepare/run
> function need access it.

type NodeImpl interface {
Prepare()
Run()
}

type Spawn struct {
//whatever, has Prepare, Run methods
}

func NewSpawn() *Spawn {...}

type Node struct {
NodeImpl
//etc
}

func NewSpawnNode() *Node {
return &Node{NewSpawn(), ...}
}

func (n *Node) DoSomeWork() {
//...
n.Prepare()
//....
n.Run()
//...
}

Then NewSpawnNode().DoSomeWork() calls the Prepare and Run methods of Spawn

nsf

unread,
Nov 19, 2010, 4:47:24 AM11/19/10
to golan...@googlegroups.com
Frankly, I don't understand why people in this thread keep pointing to
the type embedding, when it has nothing to do with functionality, but
addresses the data composition problem.

The code in the first thread post contains no data whatsoever. And can
be written that way:

type Node interface {
Prepare()
Run()
}

func doSomeWork(n Node) {
// ...
n.Prepare()
// ...
n.Run()
// ...
}

type Command struct {}

func (Command) Prepare() {
// ...
}

func (Command) Run() {
// ...
}

type Spawner struct {}

func (Spawner) Prepare() {
// ...
}

func (Spawner) Run() {
// ...
}

jimmy frasche

unread,
Nov 19, 2010, 4:55:29 AM11/19/10
to nsf, golan...@googlegroups.com

That's a fair point, and I suppose I jumped to type embedding because
it seemed like there was an implied desire was to create an object
that had several methods that used the same Node over and over and,
wrapping it to create more complex functionality out of a small set of
methods, and the assumption that the posted code was a simplified
sketch of what the OP wanted and not the complete implementation. But
Node could just as easily be a regular member or a parameter to a
method or function. Depends on how it's being used and why.

Googol Lee

unread,
Nov 19, 2010, 7:01:35 AM11/19/10
to golang-nuts
The code I show is abstract from the real code, to show the key point.
The real code has a lot of common behavior and data between children
of Node class, which need be accessed by doSomeWork function. Without
a base class, It need to repeat implement many times.

chris dollin

unread,
Nov 19, 2010, 7:09:01 AM11/19/10
to Googol Lee, golang-nuts
On 19 November 2010 12:01, Googol Lee <goog...@gmail.com> wrote:
> The code I show is abstract from the real code, to show the key point.
> The real code has a lot of common behavior and data between children
> of Node class, which need be accessed by doSomeWork function. Without
> a base class, It need to repeat implement many times.

You don't need a "base class". You need a type with some data and
some methods. The "children of Node class" can refer to an instance
of that type to get their common data & behaviour. They may embed
that instance, or not, as they see fit. The "children" can even use plain
ordinary functions for the "common behaviour".

Googol Lee

unread,
Nov 19, 2010, 7:25:30 AM11/19/10
to golang-nuts
I try to implement the code separated the common part from struct, as
your said:

type Node struct {
...
}

func (node *Node) someCommonMethod () {
...
}

type Work interface {
func prepare();
func work();
}

type Command struct {
Node
}

func (command *Command) prepare() {
...
}

func (command *Command) work() {
...
}

But how the dispatch work? Function dispatch need call
someCommonMethod and prepare/work. How can I write the signature?

On Nov 19, 8:09 pm, chris dollin <ehog.he...@googlemail.com> wrote:

jimmy frasche

unread,
Nov 19, 2010, 7:31:28 AM11/19/10
to Googol Lee, golang-nuts
On Fri, Nov 19, 2010 at 4:25 AM, Googol Lee <goog...@gmail.com> wrote:
> I try to implement the code separated the common part from struct, as
> your said:
>
> type Node struct {
> ...
> }
>
> func (node *Node) someCommonMethod () {
> ...
> }
>
> type Work interface {
> func prepare();
> func work();
> }

You don't need func or the semicolons here

> type Command struct {
> Node
> }

You need to embed the Work interface in Node and not Node in Command
(also you'd have to embed *Node since that's what has the methods on
it) and once you do that you call work and prepare like any other
method of Node. It may seem backwards, coming from a traditional OO
background. There's good info in the Go spec on embedding. You should
also read Effective Go if you haven't yet.

> func (command *Command) prepare() {
> ...
> }
>
> func (command *Command) work() {
> ...
> }

I think you'll need to explain exactly what you're trying to do and
why because it's not entirely clear if we're just talking about
syntax.

Reply all
Reply to author
Forward
0 new messages