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

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

2.2 Middle🔥 162 комментариев
#ООП и паттерны проектирования

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

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

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

Распространённые паттерны проектирования GOF в C# Backend‑разработке

За годы работы с C# и .NET я активно применял классические паттерны из каталога Gang of Four (GOF), адаптируя их к особенностям платформы и современных архитектур. Вот наиболее часто используемые категории и примеры их реализации.

Порождающие паттерны (Creational)

Эти паттерны отвечают за создание объектов, обеспечивая гибкость и инкапсуляцию процесса.

  1. Singleton (Одиночка) — несмотря на известные проблемы с тестированием, применяется для создания единственного экземпляра сервиса, который должен быть глобально доступен (например, логгер, кэш в памяти, конфигурация приложения). В современных .NET‑приложениях его роль часто берут на себя DI‑контейнеры, регистрирующие сервисы как AddSingleton.

    public sealed class AppConfig
    {
        private static readonly Lazy<AppConfig> _instance =
            new Lazy<AppConfig>(() => new AppConfig());
    
        public static AppConfig Instance => _instance.Value;
    
        private AppConfig() { } // Приватный конструктор
    
        public string ConnectionString { get; set; }
    }
    
  2. Factory Method (Фабричный метод) — используется, когда создание объекта должно делегироваться подклассам. Часто встречается в библиотеках, например, в DbContext Entity Framework Core, где фабричный метод OnConfiguring позволяет настроить подключение к БД.

    public abstract class DocumentProcessor
    {
        // Фабричный метод
        protected abstract IDocumentParser CreateParser();
    
        public void Process()
        {
            var parser = CreateParser(); // Создание через наследника
            parser.Parse();
        }
    }
    
    public class PdfProcessor : DocumentProcessor
    {
        protected override IDocumentParser CreateParser() => new PdfParser();
    }
    
  3. Abstract Factory (Абстрактная фабрика) — полезен для создания семейств взаимосвязанных объектов без привязки к конкретным классам. Пример — абстракция над разными поставщиками данных (SQL, NoSQL).

    public interface IDbFactory
    {
        IConnection CreateConnection();
        ICommand CreateCommand();
    }
    
    public class SqlServerFactory : IDbFactory
    {
        public IConnection CreateConnection() => new SqlConnection();
        public ICommand CreateCommand() => new SqlCommand();
    }
    
  4. Builder (Строитель) — идеален для пошагового создания сложных объектов с множеством опциональных параметров. Широко применяется для конфигурации (HostBuilder, WebApplicationBuilder в ASP.NET Core) или построения сложных DTO/запросов.

    public class QueryBuilder
    {
        private string _select = "*";
        private string _where = "";
    
        public QueryBuilder Select(string fields) { _select = fields; return this; }
        public QueryBuilder Where(string condition) { _where = $" WHERE {condition}"; return this; }
    
        public string Build() => $"SELECT {_select} FROM Table{_where}";
    }
    
    // Использование
    var query = new QueryBuilder().Select("Id, Name").Where("Age > 18").Build();
    

Структурные паттерны (Structural)

Паттерны этой группы отвечают за композицию классов и объектов.

  1. Adapter (Адаптер) — постоянно используется для интеграции сторонних библиотек или legacy‑кода, преобразуя их интерфейс в ожидаемый клиентом. Например, адаптер для старой системы логирования под новый интерфейс ILogger.

    public interface IModernLogger
    {
        void LogInfo(string message);
    }
    
    public class LegacyLoggerAdapter : IModernLogger
    {
        private readonly LegacyLogger _legacyLogger;
    
        public LegacyLoggerAdapter(LegacyLogger logger) => _legacyLogger = logger;
    
        public void LogInfo(string message) => _legacyLogger.WriteLog($"INFO: {message}");
    }
    
  2. Decorator (Декоратор) — один из ключевых паттернов для добавления поведения объектам без изменения их класса. В C# часто реализуется через композицию и внедрение зависимостей. Классический пример — добавление кэширования, логирования или валидации к сервису.

    public interface IDataService
    {
        string GetData();
    }
    
    public class CacheDecorator : IDataService
    {
        private readonly IDataService _innerService;
        private readonly ICache _cache;
    
        public CacheDecorator(IDataService service, ICache cache)
        {
            _innerService = service;
            _cache = cache;
        }
    
        public string GetData()
        {
            var key = "data_key";
            if (_cache.TryGet(key, out string data)) return data;
    
            data = _innerService.GetData(); // Вызов основного сервиса
            _cache.Set(key, data);
            return data;
        }
    }
    
  3. Facade (Фасад) — упрощает работу со сложными подсистемами, предоставляя единый удобный интерфейс. Типичный пример — сервис для работы с заказом (OrderService), который внутри координирует вызовы InventoryService, PaymentService и ShippingService.

    public class OrderFacade
    {
        private readonly IInventoryService _inventory;
        private readonly IPaymentService _payment;
        private readonly IShippingService _shipping;
    
        public OrderFacade(IInventoryService inv, IPaymentService pay, IShippingService ship)
        {
            _inventory = inv; _payment = pay; _shipping = ship;
        }
    
        public bool PlaceOrder(Order order)
        {
            if (!_inventory.CheckStock(order)) return false;
            if (!_payment.ProcessPayment(order)) return false;
            _shipping.ScheduleDelivery(order);
            return true;
        }
    }
    

Поведенческие паттерны (Behavioral)

Эти паттерны определяют взаимодействие между объектами и распределение ответственности.

  1. Strategy (Стратегия) — чрезвычайно полезен для инкапсуляции алгоритмов и возможности их динамической замены. Часто применяется для различных способов вычисления (IDiscountStrategy), валидации (IValidationStrategy) или сериализации (ISerializer).

    public interface ISortStrategy<T>
    {
        IEnumerable<T> Sort(IEnumerable<T> data);
    }
    
    public class QuickSortStrategy<T> : ISortStrategy<T> { /* реализация */ }
    public class MergeSortStrategy<T> : ISortStrategy<T> { /* реализация */ }
    
    public class Sorter<T>
    {
        private ISortStrategy<T> _strategy;
        public void SetStrategy(ISortStrategy<T> strategy) => _strategy = strategy;
        public IEnumerable<T> ExecuteSort(IEnumerable<T> data) => _strategy.Sort(data);
    }
    
  2. Observer (Наблюдатель) — фундаментальный паттерн для реализации событийной модели. В C# он встроен в язык через механизм событий (events) и делегатов. Широко используется для уведомлений об изменениях состояния (например, в паттерне MVVM или для доменных событий).

    public class OrderProcessor
    {
        public event EventHandler<OrderEventArgs> OrderProcessed; // Объявление события
    
        public void Process(Order order)
        {
            // Логика обработки...
            OnOrderProcessed(new OrderEventArgs(order));
        }
    
        protected virtual void OnOrderProcessed(OrderEventArgs e) =>
            OrderProcessed?.Invoke(this, e); // Вызов события
    }
    
  3. Command (Команда) — инкапсулирует запрос как объект, что позволяет параметризовать клиентов различными запросами, ставить их в очередь, логировать и поддерживать отмену операций. Применяется в системах с транзакциями, job‑очередях или для реализации undo/redo.

    public interface ICommand
    {
        void Execute();
        void Undo();
    }
    
    public class UpdateUserCommand : ICommand
    {
        private readonly UserService _service;
        private User _oldState, _newState;
    
        public UpdateUserCommand(UserService service, User newState)
        {
            _service = service;
            _newState = newState;
        }
    
        public void Execute()
        {
            _oldState = _service.GetUser(_newState.Id);
            _service.Update(_newState);
        }
    
        public void Undo() => _service.Update(_oldState);
    }
    

Заключение

Выбор паттерна всегда определяется конкретной задачей и контекстом. В современных ASP.NET Core‑приложениях многие проблемы, которые раньше решались «вручную» через GOF‑паттерны, теперь элегантно решаются встроенными механизмами: внедрение зависимостей (DI) заменяет фабрики и упрощает декораторы, Middleware‑пайплайн является разновидностью Chain of Responsibility, а система событий (EventBus) часто реализует Observer или Mediator.

Однако глубокое понимание этих классических паттернов остаётся критически важным. Оно позволяет:

  • Осознанно использовать встроенные возможности фреймворка.
  • Эффективно проектировать собственную бизнес‑логику.
  • Читать и понимать архитектуру сторонних библиотек.
  • Применять гибридные решения, комбинируя паттерны для решения сложных задач.

Таким образом, GOF‑паттерны — это не набор догм, а словарь для описания и решения архитектурных проблем, который остаётся актуальным даже в контексте современных фреймворков и парадигм.

Какие паттерны проектирования GOF использовал? | PrepBro