← Назад к вопросам

Какие GOF паттерны используешь в работе?

2.8 Senior🔥 111 комментариев
#ASP.NET и Web API

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие GOF паттерны используешь в работе

Определение GOF паттернов

GOF (Gang of Four) паттерны — это 23 классических паттерна проектирования, описанные книгой "Design Patterns: Elements of Reusable Object-Oriented Software". Это переиспользуемые решения для классических задач в объектно-ориентированном программировании.

GOF паттерны делятся на три категории:

  • Creational — создание объектов
  • Structural — структурирование отношений между объектами
  • Behavioral — взаимодействие и распределение ответственности

Самые используемые паттерны

1. Singleton (Creational)

Один объект на всё приложение.

// Проблема: несколько экземпляров конфигурации — конфликты
public class AppConfig
{
    public static AppConfig Instance { get; } = new AppConfig();
    
    private AppConfig() { }  // Private конструктор
    
    public string ConnectionString { get; set; }
}

// Использование
AppConfig.Instance.ConnectionString = "Server=localhost";

// Все части приложения используют ОДИН объект
var config1 = AppConfig.Instance;
var config2 = AppConfig.Instance;
Console.WriteLine(ReferenceEquals(config1, config2));  // true

Где используется: конфигурация приложения, логирование, кэширование.

2. Factory (Creational)

Создание объектов через фабрику, а не через конструктор.

// Проблема: зависимость от конкретных классов
public class OrderProcessor
{
    public Payment CreatePayment(string type)
    {
        return type switch
        {
            "credit" => new CreditCardPayment(),
            "paypal" => new PayPalPayment(),
            "crypto" => new CryptoPayment(),
            _ => throw new ArgumentException("Unknown type")
        };
    }
}

// Использование
var processor = new OrderProcessor();
var payment = processor.CreatePayment("credit");
payment.Process();

// Преимущество: добавляя новый тип платежа, меняем только фабрику

Где используется: создание разных типов объектов, различные БД, различные логирование.

3. Strategy (Behavioral)

Различные алгоритмы, выбираемые во время выполнения.

// Стратегия для разных способов сортировки
public interface ISortStrategy
{
    void Sort(List<int> data);
}

public class QuickSort : ISortStrategy
{
    public void Sort(List<int> data)
    {
        Console.WriteLine("Sorting with QuickSort");
        // Реализация QuickSort
    }
}

public class MergeSort : ISortStrategy
{
    public void Sort(List<int> data)
    {
        Console.WriteLine("Sorting with MergeSort");
        // Реализация MergeSort
    }
}

public class DataSorter
{
    private ISortStrategy _strategy;
    
    public DataSorter(ISortStrategy strategy)
    {
        _strategy = strategy;
    }
    
    public void SortData(List<int> data)
    {
        _strategy.Sort(data);  // Используем выбранную стратегию
    }
}

// Использование
var data = new List<int> { 5, 2, 8, 1 };
var sorter = new DataSorter(new QuickSort());
sorter.SortData(data);  // Быстро переключаемся между алгоритмами

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

4. Observer (Behavioral)

Уведомление множества объектов об изменении.

// Publisher
public class DataStore
{
    private int _value;
    public event EventHandler<int> ValueChanged;
    
    public int Value
    {
        get => _value;
        set
        {
            _value = value;
            ValueChanged?.Invoke(this, value);  // Уведомляем подписчиков
        }
    }
}

// Subscribers
public class Logger
{
    public void OnValueChanged(object sender, int newValue)
    {
        Console.WriteLine($"Value changed to {newValue}");
    }
}

public class Validator
{
    public void OnValueChanged(object sender, int newValue)
    {
        if (newValue < 0)
            Console.WriteLine("Invalid value!");
    }
}

// Использование
var store = new DataStore();
var logger = new Logger();
var validator = new Validator();

store.ValueChanged += logger.OnValueChanged;
store.ValueChanged += validator.OnValueChanged;

store.Value = 42;  // Оба подписчика будут уведомлены

Где используется: event-driven приложения, реактивное программирование, publish-subscribe.

5. Decorator (Structural)

Добавление функциональности объекту без изменения его класса.

// Базовая операция
public interface IDataProcessor
{
    void Process();
}

public class SimpleProcessor : IDataProcessor
{
    public void Process()
    {
        Console.WriteLine("Processing data");
    }
}

// Декораторы
public class CompressionDecorator : IDataProcessor
{
    private IDataProcessor _processor;
    
    public CompressionDecorator(IDataProcessor processor)
    {
        _processor = processor;
    }
    
    public void Process()
    {
        Console.WriteLine("Compressing...");
        _processor.Process();
        Console.WriteLine("Compressed");
    }
}

public class EncryptionDecorator : IDataProcessor
{
    private IDataProcessor _processor;
    
    public EncryptionDecorator(IDataProcessor processor)
    {
        _processor = processor;
    }
    
    public void Process()
    {
        Console.WriteLine("Encrypting...");
        _processor.Process();
        Console.WriteLine("Encrypted");
    }
}

// Использование: складываем декораторы как в пирог
var processor = new SimpleProcessor();
processor = new CompressionDecorator(processor);
processor = new EncryptionDecorator(processor);

processor.Process();
// Output:
// Encrypting...
// Compressing...
// Processing data
// Compressed
// Encrypted

Где используется: логирование, кэширование, валидация, форматирование.

6. Repository (Structural + Behavioral)

Абстракция доступа к данным.

public interface IUserRepository
{
    User GetById(int id);
    void Save(User user);
    void Delete(int id);
}

public class UserRepository : IUserRepository
{
    private readonly DbContext _context;
    
    public User GetById(int id)
    {
        return _context.Users.FirstOrDefault(u => u.Id == id);
    }
    
    public void Save(User user)
    {
        if (user.Id == 0)
            _context.Users.Add(user);
        else
            _context.Users.Update(user);
        
        _context.SaveChanges();
    }
    
    public void Delete(int id)
    {
        var user = GetById(id);
        if (user != null)
        {
            _context.Users.Remove(user);
            _context.SaveChanges();
        }
    }
}

// Использование: бизнес-логика не знает, что это БД
public class UserService
{
    private IUserRepository _repository;
    
    public UserService(IUserRepository repository)
    {
        _repository = repository;
    }
    
    public void UpdateUser(int id, string name)
    {
        var user = _repository.GetById(id);
        user.Name = name;
        _repository.Save(user);
    }
}

Где используется: доступ к БД, работа с файлами, API.

7. Dependency Injection (Structural)

Передача зависимостей через конструктор вместо создания внутри.

// ❌ НЕПРАВИЛЬНО: класс создаёт свои зависимости
public class UserService
{
    private IUserRepository _repository = new UserRepository();  // Привязан к конкретной реализации
    
    public User GetUser(int id) => _repository.GetById(id);
}

// ✅ ПРАВИЛЬНО: зависимости передаются
public class UserService
{
    private IUserRepository _repository;
    
    public UserService(IUserRepository repository)  // Dependency Injection
    {
        _repository = repository;
    }
    
    public User GetUser(int id) => _repository.GetById(id);
}

// Использование
var repository = new UserRepository();
var service = new UserService(repository);

// Легко тестировать с mock
var mockRepository = new MockUserRepository();
var testService = new UserService(mockRepository);

Где используется: везде в современных приложениях (ASP.NET Core, .NET 6+).

8. Adapter (Structural)

Преобразование интерфейса одного класса в интерфейс другого.

// Старый класс (legacy)
public class OldPaymentGateway
{
    public string PayWithCard(string cardNumber, decimal amount)
    {
        return $"Paid {amount} with {cardNumber}";
    }
}

// Новый интерфейс
public interface IPaymentProcessor
{
    PaymentResult Process(PaymentDetails details);
}

// Адаптер
public class PaymentAdapter : IPaymentProcessor
{
    private OldPaymentGateway _gateway = new OldPaymentGateway();
    
    public PaymentResult Process(PaymentDetails details)
    {
        var result = _gateway.PayWithCard(details.CardNumber, details.Amount);
        return new PaymentResult { Success = true, Message = result };
    }
}

// Использование
IPaymentProcessor processor = new PaymentAdapter();
var result = processor.Process(new PaymentDetails { CardNumber = "1234", Amount = 99 });

Где используется: интеграция с legacy кодом, работа с различными API.

Таблица используемых паттернов в работе

ПаттернКогда использоватьПример в C#
Singleton1 объект на всё приложениеAppConfig, Logger
FactoryСоздание разных типов объектовPaymentFactory, LoggerFactory
StrategyРазличные алгоритмыSortStrategy, CompressionStrategy
ObserverРеакция на событияEventHandler, IObserver<T>
DecoratorДобавление функциональностиCompression, Encryption
RepositoryАбстракция БДUserRepository, ProductRepository
Dependency InjectionГибкость и тестируемостьConstructor Injection в ASP.NET Core
AdapterСовместимость интерфейсовThirdPartyLibraryAdapter

Важные моменты

1. Не переусложняй

Используй паттерны только когда они решают реальную задачу, а не "на будущее".

2. Комбинируй паттерны

Часто используются вместе: Repository + Dependency Injection + Factory.

3. Язык C# облегчает

Встроенная поддержка events, delegates, interfaces делает паттерны естественными.

Краткие выводы

  1. Singleton — одна конфигурация
  2. Factory — гибкое создание объектов
  3. Strategy — выбор алгоритма во время выполнения
  4. Observer — реакция на события
  5. Repository — абстракция доступа к данным
  6. Dependency Injection — независимость и тестируемость

Золотое правило: Изучи паттерны, поймёшь проблемы, которые они решают. Используй их целенаправленно, не "потому что модно".