Этот вопрос касается архитектурного принципа зависимости от абстракций и напрямую влияет на:
Рекомендуемый подход в Go согласно философии "интерфейсы должны быть там, где они используются".
Пример:
// consumer/processor.go
package consumer
type Storage interface {
Get(id string) ([]byte, error)
Put(id string, data []byte) error
}
func ProcessData(s Storage, id string) error {
data, err := s.Get(id)
// ...
}
Преимущества:
Традиционный подход из других языков, но менее гибкий в Go:
// storage/storage.go
package storage
type Storage interface {
Get(id string) ([]byte, error)
Put(id string, data []byte) error
// +10 методов, которые могут не нужны потребителю
}
type FileStorage struct{...}
func New() Storage {
return &FileStorage{}
}
Проблемы:
io.Reader
, http.Handler
) - когда нужно соблюдение контракта// Потребитель определяет минимальный интерфейс
package notifier
type AlertSender interface {
Send(msg string) error
}
func CheckAndNotify(sender AlertSender) {
// использует только Send()
}
// Реализация в отдельном пакете может иметь больше методов
package smsnotifier
type SMSService struct{...}
func (s *SMSService) Send(msg string) error {...}
func (s *SMSService) Configure(params ...) {...} // внутренний метод
в Go интерфейсы лучше определять в месте использования, чтобы минимизировать зависимости и обеспечить гибкость. Это один из ключевых паттернов идиоматичного Go-кода.