What does this mean for Go?

In Chapter 1Never Stop Aiming for Better, we mentioned the popular Go idiom coined by Jack Lindamoodaccept interfaces, return structs. Combine this idea with the ISP and things start to take off. The resultant functions are very concise about their requirements and, at the same time, they are quite explicit regarding their outputs. In other languages, we might have to define the outputs in the form of an abstraction or create adapter classes to decouple our function from our users entirely. However, given Go's support for implicit interfaces, there is no need for this.

Implicit interfaces are a language feature whereby the implementor (that is, the struct) does not need to define the interfaces that it implements, but rather only needs to define the appropriate methods to satisfy the interface, as shown in the following code:

type Talker interface {
SayHello() string
}

type Dog struct{}

// The method implicitly implements the Talker interface
func (d Dog) SayHello() string {
return "Woof!"
}

func Speak() {
var talker Talker
talker = Dog{}

fmt.Print(talker.SayHello())
}

This might seem like a neat trick to cut down on typing, and it is. However, that is not the only reason to use it. When using explicit interfaces, the implementing object becomes somewhat coupled with its dependents as there is a rather explicit link between them. However, perhaps the most significant reason is simplicity. Let's look at one of the most popular interfaces in Go that you've probably never heard of:

// Stringer is implemented by any value that has a String method, which 
// defines the “native” format for that value. The String method is used
// to print values passed as an operand to any format that accepts a
// string or to an unformatted printer such as Print.

type Stringer interface {
String() string
}

This interface might not look impressive, but the fact that the fmt package supports this interface allows you to do the following:

func main() {
kitty := Cat{}

fmt.Printf("Kitty %s", kitty)
}

type Cat struct{}

// Implicitly implement the fmt.Stringer interface
func (c Cat) String() string {
return "Meow!"
}

If we had explicit interfaces, imagine how many times we would have to declare that we implement Stringer. Perhaps where implicit interfaces give us the most significant advantage in Go is when they are combined with the ISP and DI. The combination of the three allows us to define input interfaces that are thin, specific to the particular use case, and decoupled from everything else, as we saw with the Stringer interface.

Furthermore, defining interfaces in the package in which they are used narrows the scope of knowledge required to work on a piece of code, which in turn makes it much easier to understand and test.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.74.66