Open2
Goのジェネリクスを使ったテクニック

Decoratorパターンを構造体のレシーバに適用する方法
GoでDIを行うとき、処理は関数ではなく構造体のレシーバで行うため、Decoratorパターンで処理をラップするには一工夫が必要です。
type Usecase[T any] interface {
Execute(c context.Context, param T) error
}
func WithEventLog[T any](uc Usecase[T], eventLogParam eventLog.Param) Usecase[T] {
return usecaseWithLog[T]{uc: uc, eventLogParam: eventLogParam}
}
type usecaseWithLog[T any] struct {
uc Usecase[T]
eventLogParam eventLog.Param
}
func (u usecaseWithLog[T]) Execute(c context.Context, param T) error {
if err := u.uc.Execute(c, param); err != nil {
return err
}
return eventlog.Send(u.eventLogParam)
}
レシーバは現時点でジェネリクス非対応のため、interface自体の型パラメータを使ってレシーバの多態性を表現する。
また、関数の可変調引数をジェネリクスで表現することはできないので、代わりにstructのフィールドを使って複数の引数を表現する。
これによって任意の数の引数を取るusecaseをジェネリクスを使って表現できるようになる!
他の言語と比べると結構回りくどいけど、実現可能。