Какие группы паттернов проектирования существуют
Что проверяют
Знаете ли вы классическую классификацию и понимаете ли, как паттерны выглядят в языке без классов и наследования. Следом почти всегда просят показать, где паттерн уже живёт в стандартной библиотеке Go.
Как отвечать
Классика из книги «банды четырёх» делит 23 паттерна на три группы. Каждую стоит сразу показать на Go:
- порождающие: как создавать объекты. В Go это функции-конструкторы
NewServer, функциональные опцииWithTimeout(...)вместо Builder,sync.Onceдля ленивой единственной инициализации вместо классического Singleton; - структурные: как собирать объекты в более крупные. Адаптер это
http.HandlerFunc, который превращает обычную функцию вhttp.Handler. Декоратор это middleware видаfunc(http.Handler) http.Handler. Встраивание структур даёт композицию, а не наследование; - поведенческие: как объекты взаимодействуют. Стратегия реализуется интерфейсом или просто параметром-функцией, итератор с версии 1.23 встроен в язык через
iter.Seqиrangeпо функции, Observer часто заменяется каналом.
Для Go уместно добавить четвёртую группу, паттерны конкурентности: worker pool, pipeline, fan-out и fan-in, семафор на буферизованном канале, errgroup для группы задач с общей отменой через context.
Архитектурные паттерны вроде слоистой архитектуры или микросервисов к классификации GoF не относятся. Их можно назвать, но отдельно, как другой уровень решений.
Хорошо звучит мысль, что многие паттерны GoF в Go растворяются в языке: неявная реализация интерфейсов и функции первого класса делают целые классы-обёртки ненужными. Интерфейсы при этом объявляют на стороне потребителя и держат маленькими, как io.Reader.
Где спотыкаются
Переносят Java-стиль целиком: фабрика фабрик, абстрактные базовые «классы» через встраивание, интерфейс на каждую структуру заранее. Для Go это лишний код.
Делают Singleton глобальной переменной с проверкой на nil без синхронизации. При конкурентном вызове инициализация выполнится дважды, а детектор гонок это покажет.
Путают встраивание с наследованием и ждут переопределения методов. Метод встроенной структуры не видит методов внешней, поэтому шаблонный метод так не работает.