Golang: ООП или функциональщина?

Пользователь

от eugene.a.nail , в категории: Общие вопросы , 3 месяца назад

[ 1 ] Что в языке считается наиболее правильным и адекватным способом управления структурой логики проекта в плане соотношения ООП и функциональной составляющей?


В качестве пет-проекта пишу MVC-фреймворк. Представим, что мне нужно сделать контроллер.

Я вижу два способа:

1) Контроллера как такового нет, а хендлеры --- это публичные функции пакета.

Все зависимости (бд, сервисы, DAO) передаются в функцию пакета, а она возвращает функцию сигнатуры http.HandleFunc;

2) Контроллер --- это структура с методами, соответствующими сигнатуре http.HandleFunc. Зависимости передаются в структуру при инициализации.


[ 2 ] Как предпочтительнее комбинировать объекты и функции?

Представим, что есть структура Worker с определенным набором данных и методом Run().

[ 3 ] Если функции, вызываемые в Run(), используют данные объекта, их следует писать как методы воркера или как функции пакета?

[ 4 ] А что, если функция требует *sql.DB, который есть в воркере? Должен ли я писать эту функцию в виде метода или писать ее в виду функции пакета, принимающей в аргументы *sql.DB?

Facebook Vk Ok Twitter LinkedIn Telegram Whatsapp Pocket

1 ответ

Пользователь

от elena , 2 месяца назад

@eugene.a.nail относительно структура контроллера в MVC-фреймворка, то есть два подхода:

Подход 1: Функции пакета

Контроллер как таковой отсутствует, и обработчики являются публичными функциями пакета. Зависимости (например, база данных, сервисы, DAO) передаются в функцию пакета, а она возвращает функцию с сигнатурой http.HandleFunc.

1
2
3
4
5
func NewHandler(db *sql.DB, service *Service) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Обработка запроса с использованием db и service
    }
}


Подход 2: Структура контроллера

Контроллер представляет собой структуру с методами, которые соответствуют сигнатуре http.HandleFunc. Зависимости передаются в структуру при инициализации.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type Controller struct {
    db      *sql.DB
    service *Service
}


func NewController(db *sql.DB, service *Service) *Controller {
    return &Controller{db: db, service: service}
}


func (c *Controller) Handler(w http.ResponseWriter, r *http.Request) {
    // Обработка запроса с использованием c.db и c.service
}


относительно работы с *sql.DB и если функция требует *sql.DB, который есть в Worker, то тут возможны оба подхода:

Если функция логически связана с объектом и часто используется в его контексте, можно сделать её методом.

1
2
3
4
5
6
7
8
type Worker struct {
    db *sql.DB
    // другие поля
}

func (w *Worker) QueryData() {
    // Использование w.db
}


Если функция более универсальна и может быть полезна в других контекстах, лучше сделать её функцией пакета, принимающей *sql.DB.

1
2
3
func QueryData(db *sql.DB) {
    // Использование db
}