背景:假设我有个系统可以发送短信和邮箱的时候 使用wire应该怎么注入呢?
定义一个发送接口
type IHandler interface {
Name() string
Do(ctx context.Context) error
}
然后分别实现短信和邮箱的发送逻辑
// Sms 发送短信
type Sms struct {
}
func NewSms() IHandler {
return &Sms{}
}
func (s Sms) Name() string {
return "sms"
}
func (s Sms) Do(ctx context.Context) error {
fmt.Println("do sms")
return nil
}
// Email 发送邮箱
type Email struct {
}
func NewEmail() IHandler {
return &Email{}
}
func (s Email) Name() string {
return "email"
}
func (s Email) Do(ctx context.Context) error {
fmt.Println("do email")
return nil
}
然后注入到wire
var ProviderSet = wire.NewSet(
NewSms,
NewEmail,
)
func wireApp() *App {
panic(wire.Build(
ProviderSet,
newApp,
))
}
执行wire 我们发现报错了提示我们不能重复一个接口注入多个实现
那么我们正确的应该怎么做呢?
加入一个Manager结构体来管理我们的多个实现
type Manager struct {
hmap map[string]IHandler
}
func NewManager(
sms *Sms,
email *Email,
) *Manager {
hmap := make(map[string]IHandler)
hmap[sms.Name()] = sms
hmap[email.Name()] = email
return &Manager{hmap: hmap}
}
func (m Manager) Get(name string) (IHandler, error) {
if v, ok := m.hmap[name]; ok {
return v, nil
}
return nil, errors.New("unknown handle")
}
然后修改原来的短信sms和邮箱email的实现返回具体实现而不是返回接口
// Sms 发送短信
type Sms struct {
}
func NewSms() *Sms {
return &Sms{}
}
func (s Sms) Name() string {
return "sms"
}
func (s Sms) Do(ctx context.Context) error {
fmt.Println("do sms")
return nil
}
// Email 发送邮箱
type Email struct {
}
func NewEmail() *Email {
return &Email{}
}
func (s Email) Name() string {
return "email"
}
func (s Email) Do(ctx context.Context) error {
fmt.Println("do email")
return nil
}
然后注入到wire
var ProviderSet = wire.NewSet(
NewSms,
NewEmail,
NewManager,
)
func wireApp() *App {
panic(wire.Build(
ProviderSet,
newApp,
))
}
生成的wire_gen.go
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
// Injectors from wire.go:
func wireApp() *App {
sms := NewSms()
email := NewEmail()
manager := NewManager(sms, email)
app := newApp(manager)
return app
}
我们发现执行正常了
写个方法测试一下
func main() {
app := wireApp()
ctx := context.Background()
var h IHandler
h, _ = app.manager.Get("sms")
fmt.Println(h.Name())
h.Do(ctx)
h, _ = app.manager.Get("email")
fmt.Println(h.Name())
h.Do(ctx)
}
这样我们增加发送方法就只需要在NewManager往后增加就行了