Introduction
Using a fluent interface can make your code easier to read. This pattern allows you to connect method calls, as each method returns the object or context. When implemented well, it can create a kind of specialized language for a specific domain.
Let’s see how this works in Go
Implementation in Go
For this example we will implement a simple fluent interface on an Address
-struct:
type Address struct {
street string
number int32
extension string
city string
country string
}
Note how all the field names are spelled with a lower-case first letter. That is the Go-way to make fields and also methods private.
We also need some type of constructor:
func CreateEmptyAddress() *Address {
return &Address{}
}
Next we implement our fluent interface:
func (a *Address) SetStreet(streetName string) *Address {
a.street = streetName
return a
}
func (a *Address) SetNumber(number int32) *Address {
a.number = number
return a
}
func (a *Address) SetExtension(extension string) *Address {
a.extension = extension
return a
}
func (a *Address) SetCity(city string) *Address {
a.city = city
return a
}
func (a *Address) SetCountry(country string) *Address {
a.country = country
return a
}
A few notes:
- Each method sets a field in the object and returns the object itself, allowing method chaining.
- Typically, these methods would be placed in a separate package or file.
We also need a small utility method to display the address:
func (a *Address) Display() {
if a.extension == "" {
fmt.Printf("%s %d in %s, %s\n", a.street, a.number, a.city, a.country)
} else {
fmt.Printf("%s %d%s in %s, %s\n", a.street, a.number, a.extension, a.city, a.country)
}
}
Testing
Now we can test this pattern:
func main() {
address := CreateEmptyAddress().SetStreet("Middle road").SetNumber(50).SetCity("Arcadia").SetCountry("Utopia")
address.Display()
address.SetExtension("A").Display()
}
A summary:
- We create an address and using the fluent interface we set its fields.
- Then we display this address
- Again we add an extension, and using the fluent interface we can immediately display the address.
Conclusion
The fluent interface can make your code more readable and flexible, however, it might not always be the right choice for every situation. As always one must consider the trade-offs, since it might improve readability in our example, this might not always be the case, and it might even increase complexity for example in the form of unwieldy chains of method calls.