Перейти к содержимому
шпаргалка.
Esc
навигацияоткрыть⌘Jпредпросмотр
На этой странице

Паттерны

Все темы Go Developer

С какими паттернами проектирования знакомы?

Основные паттерны проектирования:

Порождающие паттерны:

  1. Singleton (Одиночка):

    • Гарантирует, что у класса есть только один экземпляр и предоставляет к нему глобальную точку доступа.
  2. Factory Method (Фабричный метод):

    • Определяет интерфейс для создания объектов, но позволяет подклассам изменять тип создаваемых объектов.
  3. Abstract Factory (Абстрактная фабрика):

    • Предоставляет интерфейс для создания семейств взаимосвязанных объектов, не специфицируя их конкретные классы.
  4. Builder (Строитель):

    • Разделяет создание сложного объекта от его представления, позволяя строить объект пошагово.
  5. Prototype (Прототип):

    • Создает объекты на основе существующего экземпляра через клонирование.

Структурные паттерны:

  1. Adapter (Адаптер):

    • Позволяет объектам с несовместимыми интерфейсами работать вместе.
  2. Bridge (Мост):

    • Разделяет абстракцию и её реализацию, чтобы они могли изменяться независимо.
  3. Composite (Компоновщик):

    • Компонует объекты в древовидные структуры для представления иерархий часть-целое.
  4. Decorator (Декоратор):

    • Добавляет новой функциональности объекту динамически.
  5. Facade (Фасад):

    • Предоставляет унифицированный интерфейс к набору интерфейсов в подсистеме.
  6. Flyweight (Приспособленец):

    • Позволяет вместить большее количество объектов, разделяя общий внутренний объект.
  7. Proxy (Заместитель):

    • Предоставляет суррогатный объект, контролирующий доступ к другому объекту.

Поведенческие паттерны:

  1. Chain of Responsibility (Цепочка обязанностей):

    • Передает запрос по цепочке обработчиков, пока один из них не обработает запрос.
  2. Command (Команда):

    • Инкапсулирует запрос в виде объекта, позволяя параметризовать клиентами с различными запросами.
  3. Interpreter (Интерпретатор):

    • Определяет грамматику языка и интерпретирует предложения этого языка.
  4. Iterator (Итератор):

    • Предоставляет способ последовательного доступа ко всем элементам коллекции без раскрытия её внутреннего представления.
  5. Mediator (Посредник):

    • Определяет объект, который инкапсулирует способ взаимодействия множества объектов.
  6. Memento (Хранитель):

    • Сохраняет и восстанавливает внутреннее состояние объекта, не нарушая инкапсуляции.
  7. Observer (Наблюдатель):

    • Определяет зависимость один ко многим между объектами, так что при изменении состояния одного объекта все зависимые уведомляются и обновляются.
  8. State (Состояние):

    • Позволяет объекту изменять свое поведение при изменении его внутреннего состояния.
  9. Strategy (Стратегия):

    • Определяет семейство алгоритмов, инкапсулирует их и делает их взаимозаменяемыми.
  10. Template Method (Шаблонный метод):

    • Определяет скелет алгоритма в методе, оставляя определенные шаги подклассам.
  11. Visitor (Посетитель):

    • Позволяет добавлять новые операции к объектам, не изменяя их классы.

Расскажите про паттерны Builder (Строитель), Factory (Фабрика), Closer (Доводчик), Singleton (Одиночка)

Примеры паттернов проектирования:

Builder (Строитель)

Цель: Разделить процесс создания сложного объекта от его представления, позволяя создавать разные представления с помощью одного и того же процесса построения.

Пример:

  • Используется для создания объектов с множеством опций или конфигураций.

  • Включает в себя отдельный объект-строитель, который поэтапно собирает конечный объект.

Пример на Go:

type House struct {
    Windows string
    Doors   string
}

type HouseBuilder struct {
    house *House
}

func NewHouseBuilder() *HouseBuilder {
    return &HouseBuilder{house: &House{}}
}

func (b *HouseBuilder) SetWindows(windows string) *HouseBuilder {
    b.house.Windows = windows
    return b
}

func (b *HouseBuilder) SetDoors(doors string) *HouseBuilder {
    b.house.Doors = doors
    return b
}

func (b *HouseBuilder) Build() *House {
    return b.house
}

// Использование
builder := NewHouseBuilder()
house := builder.SetWindows("Wooden").SetDoors("Metal").Build()

Factory (Фабрика)

Цель: Предоставить интерфейс для создания объектов, но позволяет подклассам изменять тип создаваемых объектов.

Пример:

  • Позволяет создавать объекты без указания точного класса создаваемого объекта.

  • Упрощает создание объектов и улучшает поддерживаемость кода.

Пример на Go:

type Animal interface {
    Speak() string
}

type Dog struct{}
func (d Dog) Speak() string { return "Woof" }

type Cat struct{}
func (c Cat) Speak() string { return "Meow" }

func AnimalFactory(animalType string) Animal {
    switch animalType {
    case "dog":
        return Dog{}
    case "cat":
        return Cat{}
    default:
        return nil
    }
}

// Использование
animal := AnimalFactory("dog")
fmt.Println(animal.Speak()) // Вывод: Woof

Singleton (Одиночка)

Цель: Гарантировать, что у класса есть только один экземпляр, и предоставить к нему глобальную точку доступа.

Пример:

  • Полезен, когда необходимо контролировать доступ к какому-либо ресурсу, например, к базе данных или к файлу конфигурации.

Пример на Go:

type singleton struct{}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

// Использование
s1 := GetInstance()
s2 := GetInstance()
fmt.Println(s1 == s2) // Вывод: true (оба указателя указывают на один экземпляр)

Closer (Доводчик)

Цель: Упрощение управления ресурсами, которые должны быть явно закрыты после использования (например, файлы, соединения).

Пример:

  • Часто используется для автоматического закрытия ресурсов в конце блока кода.

Пример на Go:

type Closer interface {
    Close() error
}

func UseResource(resource Closer) {
    defer resource.Close()
    // Работа с ресурсом
}

// Использование
file, err := os.Open("file.txt")
if err != nil {
    log.Fatal(err)
}
UseResource(file)

Расскажите, какой паттерн использовали в продукте/своем коде?

Ниже — учебный пример однократной загрузки конфигурации. На собеседовании опишите собственную задачу и причины выбора паттерна; Singleton не обязателен для хранения конфигурации.

Решение: Использование паттерна Singleton для управления конфигурацией.

Код:

package config

import (
    "sync"
    "encoding/json"
    "os"
)

type Config struct {
    DatabaseURL string
    Port        int
}

var instance *Config
var once sync.Once
var loadErr error

func GetConfig() (*Config, error) {
    once.Do(func() {
        instance = &Config{}
        file, err := os.Open("config.json")
        if err != nil {
            loadErr = err
            return
        }
        defer file.Close()
        loadErr = json.NewDecoder(file).Decode(instance)
    })
    return instance, loadErr
}

Использование:

package main

import (
    "fmt"
    "myapp/config"
)

func main() {
    conf, err := config.GetConfig()
    if err != nil {
        fmt.Println("Cannot load config:", err)
        return
    }
    fmt.Println("Database URL:", conf.DatabaseURL)
    fmt.Println("Port:", conf.Port)
}

Преимущества:

  • Единая точка доступа: Конфигурация загружается один раз и используется во всех частях приложения.

  • sync.Once синхронизирует однократную загрузку, включая неуспешную попытку. Возвращаемую общую Config нельзя изменять конкурентно без дополнительной защиты; автоматического повтора загрузки здесь нет.

Эта страница была полезной?