I'm trying to make several types that can call the same function to perform a few common operations, without needing to duplicate them for each type. Let's call those types handlers.
The idea is that I can have a CreateHandler, a ListHandler, etc, and a function that will do default operations for those handlers, let's say, set the "Success" field to true and call the "Execute" function on the handler. I keep those examples simple to make them easy to read, but in real case there would be way more common operations.
I've tried 3 different approaches, to no avail: using a base type and embed it, using an interface implemented by types and using an empty interface as parameter.
Base type embedded
package main
import "fmt"
type BaseHandler struct {
Success bool
}
func ( handler *BaseHandler ) Init() {
handler.Success = true
handler.Execute()
}
func ( handler *BaseHandler ) Execute() {
}
// I will have many different types doing the same kind of work,
// with their own specific fields and functions
type MyHandler struct {
BaseHandler
Message string
}
func ( handler *MyHandler ) Execute() {
fmt.Println( "I'm never called" )
}
func main() {
handler := MyHandler{}
handler.Init()
}
This won't work because the Execute
function called is the one from BaseHandler
, not from MyHandler
. Same problem if the Init
method has no receiver and takes a *BaseHandler
as parameter.
interface implemented by types
package main
import "fmt"
type BaseHandler interface {
Execute()
}
func Init( handler BaseHandler ) {
handler.Success = true
handler.Execute()
}
type MyHandler struct {
Success bool
Message string
}
func ( handler *MyHandler ) Execute() {
fmt.Println( "I'm never called" )
}
func main() {
handler := MyHandler{}
Init( handler )
}
This will fail to compile because of first line of Init
function, saying that the BaseHandler
interface does not have a Success
field.
empty interface as parameter
package main
import "fmt"
func Init( handler interface{} ) {
handler.Success = true
handler.Execute()
}
type MyHandler struct {
Success bool
Message string
}
func ( handler *MyHandler ) Execute() {
fmt.Println( "I'm never called" )
}
func main() {
handler := MyHandler{}
Init( handler )
}
This will fail to compile on first line of Init
saying that interface{}
has no Success
field. I can't do type assertion there, because it would mean listing all the types which can go there, and there may be a lot.
Question
So here is my question: how do you write shared code, that can set fields and call functions from similar types?