If an interface has only a single method, should I use a function type instead?
Here are an examples of both approaches:
type Delegate interface { | type Delegate func(x int) int Do(x int) int | } | | type App struct { | type App struct { delegate Delegate | delegate Delegate } | } | func (this *App) foo() { | func (this *App) foo() { ... | ... y := this.delegate.Do(x) | y := this.delegate(x) ... | ... } | } | func main() { | func main() { delegate := &DelegateImpl{} | delegate := &DelegateImpl{} app := &App{delegate} | app := &App{delegate.Process} ... | ... } | }
Tests:
type FakeDelegate { | t *testing.T | expectedX int | result int | } | | func (this *FakeDelegate) Do(x int) int { | require.Equal(t, this.expectedX, x) | return this.result | } | | func TestAppFoo(t *testing.T) { | func TestAppFoo(t *testing.T) { app := &App{} | app := &App{} app.delegate = &FakeDelegate{t, 1, 2} | app.delegate = func(x int) int { app.foo() | require.Equal(t, 1, x) } | return 2 | } | app.foo() | }
It looks like the code on the right (with function type) has less lines, especially when it comes to tests. But isn't there any pitfalls?
// It can contain any number of Object class methods. A functional interface can extends another interface only when it does not have any abstract method. In the following example, a functional interface is extending to a non-functional interface.
Function: The Function interface has an abstract method apply which takes argument of type T and returns a result of type R. Its prototype is A functional interface has only one abstract method but it can have multiple default methods.
An Interface that contains exactly one abstract method is known as functional interface. It can have any number of default, static methods but can contain only one abstract method. It can also declare methods of object class. Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces.
When an interface contains only one abstract method, then it is known as a Functional Interface. 2. Marker Interface: An interface that does not contain any methods, fields, Abstract Methods, and any Constants is Called a Marker interface. Also, if an interface is empty, then it is known as Marker Interface.
This is a question of design. Interfaces offer something that functions don't : dynamic dispatch. So if later on you want (possibly your own) client code to apply said function to an object, and envision that this object may possibly be of one of several different types at one given point in the program, go for an interface.
The pro : you can get flexible.
The cons :
Go is designed as a simple and pragmatic language. I suppose that as willing users, we should carry forward its philosophy. Hence, I'd say : if you don't need something, don't use it. :)
Although a function pointer is indeed a form of developer-managed dynamic dispatch, it seems to me that the reasoning above remains applicable : go for the simplest solution that could satisfy the foreseeable needs. Otherwise Go will become Java. If you're certain that the delegate will never need to provide any other entry point (like providing meta information for example), I'd say stick to the function pointer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With