Какие GOF паттерны используешь в работе?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие 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# |
|---|---|---|
| Singleton | 1 объект на всё приложение | 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 делает паттерны естественными.
Краткие выводы
- Singleton — одна конфигурация
- Factory — гибкое создание объектов
- Strategy — выбор алгоритма во время выполнения
- Observer — реакция на события
- Repository — абстракция доступа к данным
- Dependency Injection — независимость и тестируемость
Золотое правило: Изучи паттерны, поймёшь проблемы, которые они решают. Используй их целенаправленно, не "потому что модно".