Go Interface Composition
Interface composition builds a larger interface from smaller interfaces. The larger interface asks for the methods of every part.
Two small interfaces in one
Fetcher names a Fetch method. Storer names a Store method. FetchStorer lists both interfaces inside its braces.
package main
import "fmt"
type Fetcher interface {
Fetch() string
}
type Storer interface {
Store(text string)
}
type FetchStorer interface {
Fetcher
Storer
}
type Memory struct {
text string
}
func (m *Memory) Store(text string) {
m.text = text
}
func (m Memory) Fetch() string {
return m.text
}
func main() {
var store FetchStorer = &Memory{}
store.Store("Go notes")
fmt.Println(store.Fetch())
}A composed interface with Stringer
Label names a Name method. fmt.Stringer names a String method. LabelStringer lists both interfaces.
package main
import "fmt"
type Label interface {
Name() string
}
type LabelStringer interface {
Label
fmt.Stringer
}
type Product struct {
Title string
}
func (p Product) Name() string {
return p.Title
}
func (p Product) String() string {
return "Product: " + p.Title
}
func main() {
var item LabelStringer = Product{Title: "Notebook"}
fmt.Println(item.Name())
fmt.Println(item)
}A composed interface as a parameter
Actor lists Speaker and Mover. The perform function takes an Actor, so it can call Speak and Move.
package main
import "fmt"
type Speaker interface {
Speak() string
}
type Mover interface {
Move() string
}
type Actor interface {
Speaker
Mover
}
type Robot struct{}
func (r Robot) Speak() string {
return "I can speak"
}
func (r Robot) Move() string {
return "I can move"
}
func perform(a Actor) {
fmt.Println(a.Speak())
fmt.Println(a.Move())
}
func main() {
perform(Robot{})
}Example
package main
import "fmt"
type Reader interface {
Read() string
}
type Writer interface {
Write(text string)
}
type ReadWriter interface {
Reader
Writer
}
type Buffer struct {
text string
}
func (b *Buffer) Write(text string) {
b.text += text
}
func (b Buffer) Read() string {
return b.text
}
func main() {
var rw ReadWriter = &Buffer{}
rw.Write("Hello ")
rw.Write("Go")
fmt.Println(rw.Read())
}Key points
- A composed interface lists a smaller interface by its name alone.
- A type satisfies a composed interface when it has every method from every part.
- fmt.Stringer is an interface that names one method, String.
- The String method returns the text that fmt prints for a value.
- A composed interface can serve as the type of a function parameter.
- A function with that parameter can call every method the parts name.
In this example, ReadWriter lists Reader and Writer. The code stores a new Buffer in a ReadWriter value. The first Write call adds Hello with a trailing space. The second Write call adds Go. Read returns the stored text, and the print line shows Hello Go.
Note
The parts stay usable on their own beside the composed interface.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Go Playground
Exercise
A type has the Fetch method but no Store method. Can it satisfy FetchStorer?