Структурирование интерфейсов go с подпакетами

Я разрабатываю свое первое приложение для реального использования и пытаюсь разобраться, что мои кодовые файлы должны быть структурированы.

Основная часть моего кода будет состоять из нескольких типов, реализующих общий интерфейс.


type Runner interface {
  Run() string
}

Они будут в упаковке. Поскольку количество реализаций интерфейса будет очень большим, я хотел бы разделить их (семантически) на несколько подпакетов.

runner/
  blue/
  red/

Реализации Runner нужен доступ к паре других интерфейсов, которые определены в другом месте моего приложения (например, Cache и Secret). В настоящее время они определены и реализованы в отдельных пакетах. Мой план состоит в том, чтобы использовать структуру Config, содержащую все эти служебные интерфейсы, и передать ее реализациям Runner.

Я не уверен, как лучше всего обращаться с этими подпакетами и где разместить Config и объявления интерфейса. Мой интуитивный подход состоял бы в том, чтобы определить как структуру Config, так и интерфейс Runner в пакете runner и вернуть оттуда только коллекцию []Runner, но это нарушает эта рекомендация. Кроме того, количество необходимых импортов и опасность столкнуться с циклическими ссылками, которые запрещены, дают мне ощущение, что мое решение идет вразрез с передовой практикой.

Есть ли какие-либо предложения, как улучшить структуру моего кода? Было бы целесообразно добавить пакет common, который содержит все мои определения интерфейса и структуру Config?

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
2
0
38
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В итоге я создал domain пакет, содержащий интерфейс и Config определения.

Так что в domain/domain.go у меня есть

package domain


type Config struct {
    Cache
}

type Runner interface {
  Run() string
}

type Cache interface {
  // ...
}

Бегуны структурированы в подпакеты, как упоминалось выше. Я не экспортирую типы, а имею функцию в каждом пакете, собирающую их все и возвращающую в качестве интерфейсов.

runner/blue/blue.go:

package blue

import "my/domain"

func All(config domain.Config) (list []domain.Runner) {
    list = append(list, fooRunner{Config: config})
    list = append(list, barRunner{Config: config})
    return
}

runner/runner.go:

package runner

import ( 
  "my/runner/blue"
  "my/runner/red"
  "my/runner/domain"
)

func All(config domain.Config) (list []domain.Runner) {
    list = append(list, blue.All(config)...)
    list = append(list, red.All(config)...)
    return
}

Другие вопросы по теме