Либо, или ни - это на самом деле не имеет значения, на мой взгляд, потому что идиоматическое подход должен был бы организовать эти понятия с помощью интерфейса:
package user
type User ...
type Inserter interface { Insert(User) error }
type Deleter interface { Delete(User) error }
type Manager interface { Inserter, Deleter } // bloated interface
User
в этом случае, вероятно, является конкретный тип строки, как в ваш пример, но можно было бы сделать так, чтобы он тоже превратился в интерфейс, который не упоминает эти типы.
Если вы пишете функции, которые ссылаются на эти интерфейсы, вы можете быстро склеить их, используя embedding & promoted fields.
В вашем случае это очевидно, что прилипание к первому стилю реализации гораздо проще:
type userManager struct { ... }
func (userManager) Insert(u User) error { ... }
func (userManager) Delete(u User) error { ... }
userManager
является частным типа, поэтому она может быть изменена без заботы, до тех пор, как он держит удовлетворяющий открытые интерфейсы ,
Сохранение интерфейсов, отделенных от реализации, значительно упрощает их сужение, поэтому вместо того, чтобы иметь «пользовательский менеджер» или что-то еще, вы можете узнать, какие интерфейсы вам действительно нужны для задач. Кстати, этот подход имеет приятное свойство, которое хорошо сочетается с object capability model, что упрощает такие функции, как управление доступом на основе ролей.
Предлагаю перейти с первого подхода. Это делает кодовую базу более структурированной и более читаемой. Создавая экземпляр или UserManager, все приложение, которое может быть сделано на нем, будет очень четким при кодировании. –