Interface embedding and calling interface methods from another package in Go (Golang)
example2/
|-- main.go
|-- go.mod
|-- monitor/
|-- monitor.go
|-- validator/
|-- validator.go
This declares the module name example2
and specifies that this module is written in Go version 1.20.
Example
module example2
go 1.20
- This package imports the
validator
package. - It declares a struct named
Monitor
which embeds theValidator
interface from thevalidator
package. The field is nameddynamicValidator
. - There's a constructor function named
NewMonitor
which takes adeviceID
and an instance ofValidator
. It returns an instance ofMonitor
. - The
Monitor
method on theMonitor
struct simply calls theValidateLocation
method on the embeddedValidator
.
Example
package monitor
import validator "example2/validator"
type Monitor struct {
deviceID string
dynamicValidator validator.Validator
}
func NewMonitor(deviceID string, dynamicValidator validator.Validator) (*Monitor, error) {
return &Monitor{
deviceID: deviceID,
dynamicValidator: dynamicValidator,
}, nil
}
func (mon *Monitor) Monitor() error {
mon.dynamicValidator.ValidateLocation("whatever")
return nil
}
- This package declares an interface named
Validator
with a method signatureValidateLocation(location string) error
. - It also declares a private struct
validation
that implements thisValidator
interface. This struct has a fieldappID
which seems to be used for validation purposes, though the current implementation ofValidateLocation
only prints thelocation
. - There's a constructor function named
NewValidator
which takesappID
as a parameter and returns an instance ofvalidation
as aValidator
.
Example
package validator
import "fmt"
type Validator interface {
ValidateLocation(location string) error
}
type validation struct {
appID string
}
func NewValidator(
appID string,
) Validator {
return &validation{
appID: appID,
}
}
func (v *validation) ValidateLocation(location string) error {
fmt.Println(location)
return nil
}
- Both
validator
andmonitor
packages are imported with aliasesd
andm
respectively. - In the
main
function:- An instance of
Validator
is created using theNewValidator
function from thevalidator
package. - This
Validator
instance is then passed to theNewMonitor
function from themonitor
package to create aMonitor
instance. - Finally, the
Monitor
method is called on theMonitor
instance.
- An instance of
This program demonstrates the power of interfaces in Go:
-
Decoupling: The
monitor
package doesn't need to know the exact implementation of theValidator
it uses. It only cares about the methods described in theValidator
interface. This makes it easy to swap out validation implementations without changing themonitor
package. -
Composition: The
Monitor
struct in themonitor
package composes its behavior using the embeddedValidator
interface. This is a powerful way to build complex types by composing simpler ones. -
Package Organization: Each package has its responsibility:
validator
handles validation, andmonitor
monitors something (in this example, it just calls the validation). This separation of concerns makes the codebase modular and maintainable.
Example
package main
import (
"fmt"
d "example2/validator"
m "example2/monitor"
)
func main() {
// Create a validator instance
validatorInstance := d.NewValidator("your_app_id")
// Create a monitor instance with the validator validator
monitorInstance, _ := m.NewMonitor("your_device_id", validatorInstance)
// Call the Monitor method
err := monitorInstance.Monitor()
if err != nil {
fmt.Println("Error:", err)
}
}
When you run this program, it will print:
whatever
This output comes from the ValidateLocation
method in the validator
package, which is called via the Monitor
method of the monitor
package.