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

Какие знаешь структурные паттерны?

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

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

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

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

Структурные паттерны проектирования в C#

Структурные паттерны проектирования — это шаблоны, которые помогают организовать классы и объекты в более сложные и гибкие структуры, сохраняя при этом эффективность и минимальную связанность кода. В контексте C# и backend-разработки они особенно полезны для построения масштабируемых, поддерживаемых архитектур. Вот ключевые структурные паттерны, которые я активно использую:

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

Паттерн позволяет объектам с несовместимыми интерфейсами работать вместе. В backend-разработке часто применяется для интеграции сторонних библиотек или устаревших систем.

// Пример: адаптер для старой системы логирования
public interface ILogger
{
    void Log(string message);
}

public class LegacyLogger
{
    public void WriteLog(string text)
    {
        Console.WriteLine($"Legacy: {text}");
    }
}

public class LoggerAdapter : ILogger
{
    private readonly LegacyLogger _legacyLogger;
    
    public LoggerAdapter(LegacyLogger legacyLogger)
    {
        _legacyLogger = legacyLogger;
    }
    
    public void Log(string message)
    {
        _legacyLogger.WriteLog(message);
    }
}

// Использование
var legacyLogger = new LegacyLogger();
ILogger logger = new LoggerAdapter(legacyLogger);
logger.Log("Адаптированное сообщение");

2. Мост (Bridge)

Разделяет абстракцию и реализацию, позволяя им изменяться независимо. Полезен при работе с разными провайдерами (например, базы данных, платежные системы).

public interface IDataStorage // Реализация
{
    void Save(string data);
}

public abstract class DataProcessor // Абстракция
{
    protected IDataStorage _storage;
    
    protected DataProcessor(IDataStorage storage)
    {
        _storage = storage;
    }
    
    public abstract void ProcessAndSave(string data);
}

public class JsonDataProcessor : DataProcessor
{
    public JsonDataProcessor(IDataStorage storage) : base(storage) {}
    
    public override void ProcessAndSave(string data)
    {
        var json = $"{{ \"data\": \"{data}\" }}";
        _storage.Save(json);
    }
}

3. Компоновщик (Composite)

Позволяет сгруппировать объекты в древовидные структуры и работать с ними как с единым объектом. Часто используется для построения UI-компонентов или файловых систем.

public abstract class FileSystemComponent
{
    public string Name { get; }
    public abstract long GetSize();
}

public class File : FileSystemComponent
{
    private long _size;
    
    public override long GetSize() => _size;
}

public class Directory : FileSystemComponent
{
    private List<FileSystemComponent> _children = new List<FileSystemComponent>();
    
    public void Add(FileSystemComponent component)
    {
        _children.Add(component);
    }
    
    public override long GetSize()
    {
        return _children.Sum(c => c.GetSize());
    }
}

4. Декоратор (Decorator)

Динамически добавляет объекту новые обязанности. В C# часто реализуется через наследование или с использованием встроенных возможностей (например, System.IO.Stream).

public interface INotifier
{
    void Send(string message);
}

public class EmailNotifier : INotifier
{
    public void Send(string message)
    {
        Console.WriteLine($"Email: {message}");
    }
}

public abstract class NotifierDecorator : INotifier
{
    protected INotifier _notifier;
    
    protected NotifierDecorator(INotifier notifier)
    {
        _notifier = notifier;
    }
    
    public virtual void Send(string message)
    {
        _notifier.Send(message);
    }
}

public class SmsNotifierDecorator : NotifierDecorator
{
    public SmsNotifierDecorator(INotifier notifier) : base(notifier) {}
    
    public override void Send(string message)
    {
        base.Send(message);
        Console.WriteLine($"SMS: {message}");
    }
}

5. Фасад (Facade)

Представляет простой интерфейс к сложной подсистеме. В backend-разработке это типичный пример для упрощения работы с внешними API или сложными библиотеками.

public class OrderProcessingFacade
{
    private InventoryService _inventory;
    private PaymentService _payment;
    private ShippingService _shipping;
    
    public OrderProcessingFacade()
    {
        _inventory = new InventoryService();
        _payment = new PaymentService();
        _shipping = new ShippingService();
    }
    
    public void ProcessOrder(Order order)
    {
        _inventory.CheckStock(order);
        _payment.ProcessPayment(order);
        _shipping.ScheduleDelivery(order);
    }
}

6. Приспособленец (Flyweight)

Экономит память, разделяя общее состояние между множеством объектов. Полезен для работы с большими объемами данных (например, кэширование строк или графических объектов).

public class CharacterFlyweight
{
    public char Symbol { get; }
    public string FontFamily { get; }
    // Другие общие данные
}

public class FlyweightFactory
{
    private Dictionary<string, CharacterFlyweight> _flyweights = new Dictionary<string, CharacterFlyweight>();
    
    public CharacterFlyweight GetFlyweight(char symbol, string fontFamily)
    {
        string key = $"{symbol}_{fontFamily}";
        if (!_flyweights.ContainsKey(key))
        {
            _flyweights[key] = new CharacterFlyweight { Symbol = symbol, FontFamily = fontFamily };
        }
        return _flyweights[key];
    }
}

7. Заместитель (Proxy)

Предоставляет суррогатный объект, контролирующий доступ к другому объекту. В C# особенно актуален для ленивой загрузки, кэширования и контроля доступа.

public interface IImage
{
    void Display();
}

public class RealImage : IImage
{
    private string _filename;
    
    public RealImage(string filename)
    {
        _filename = filename;
        LoadFromDisk();
    }
    
    private void LoadFromDisk()
    {
        Console.WriteLine($"Загрузка {_filename}");
    }
    
    public void Display()
    {
        Console.WriteLine($"Отображение {_filename}");
    }
}

public class ImageProxy : IImage
{
    private RealImage _realImage;
    private string _filename;
    
    public ImageProxy(string filename)
    {
        _filename = filename;
    }
    
    public void Display()
    {
        if (_realImage == null)
        {
            _realImage = new RealImage(_filename);
        }
        _realImage.Display();
    }
}

Практическое применение в Backend-разработке на C#

В моей практике структурные паттерны играют ключевую роль:

  • Адаптер и Фасад часто используются при интеграции микросервисов или работе с legacy-кодом.
  • Декоратор идеален для добавления сквозной функциональности: логирование, кэширование, аутентификация.
  • Заместитель реализуется через IHttpClientFactory для управления HTTP-клиентами с политиками повторов.
  • Компоновщик полезен для построения сложных деревьев конфигураций или обработки бизнес-правил.

В современных C# фреймворках (ASP.NET Core) многие паттерны встроены "из коробки". Например, Middleware — это реализация Декоратора и Цепочки обязанностей, а Dependency Injection активно использует принципы Заместителя и Адаптера.

Важное замечание: Выбор паттерна должен определяться конкретной задачей, а не стремлением применить "модный" подход. Сверх-использование паттернов может привести к излишней сложности, тогда как их уместное применение значительно повышает поддерживаемость и тестируемость кода. В сочетании с SOLID-принципами, структурные паттерны помогают строить архитектуру, которая легко адаптируется к изменениям требований — что критически важно в долгосрочной backend-разработке.

Какие знаешь структурные паттерны? | PrepBro