Какие знаете паттерны? Объясните суть перечисленных.csharp-61

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

1.1. Singleton

Суть: Гарантирует существование только одного экземпляра класса

public sealed class Singleton
{
    private static Singleton _instance;
    private static readonly object _lock = new object();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            lock (_lock)
            {
                return _instance ??= new Singleton();
            }
        }
    }
}

Применение: Логгеры, кэши, подключения к БД

1.2. Factory Method

Суть: Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать

public abstract class Document
{
    public abstract void CreatePages();
}

public class Resume : Document
{
    public override void CreatePages()
    {
        Pages.Add(new SkillsPage());
    }
}

Применение: Плагины, кросс-платформенные UI

2. Структурные паттерны

2.1. Adapter

Суть: Преобразует интерфейс класса в другой интерфейс, ожидаемый клиентом

public interface ITarget
{
    string GetRequest();
}

public class Adaptee
{
    public string GetSpecificRequest() => "Specific request";
}

public class Adapter : ITarget
{
    private readonly Adaptee _adaptee;

    public Adapter(Adaptee adaptee) => _adaptee = adaptee;

    public string GetRequest() => _adaptee.GetSpecificRequest();
}

Применение: Интеграция legacy-кода, работа со сторонними библиотеками

2.2. Composite

Суть: Объединяет объекты в древовидные структуры

public interface IGraphic
{
    void Draw();
}

public class Circle : IGraphic { /*...*/ }

public class GraphicGroup : IGraphic
{
    private readonly List<IGraphic> _children = new();

    public void Add(IGraphic graphic) => _children.Add(graphic);
    public void Draw() => _children.ForEach(c => c.Draw());
}

Применение: UI-фреймворки, файловые системы

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

3.1. Observer

Суть: Определяет зависимость "один-ко-многим" между объектами

public interface IObserver
{
    void Update(ISubject subject);
}

public class ConcreteObserver : IObserver
{
    public void Update(ISubject subject) { /*...*/ }
}

public class Subject : ISubject
{
    private readonly List<IObserver> _observers = new();

    public void Attach(IObserver observer) => _observers.Add(observer);
    public void Notify() => _observers.ForEach(o => o.Update(this));
}

Применение: Событийные модели, MVC

3.2. Strategy

Суть: Определяет семейство алгоритмов, инкапсулирует каждый из них

public interface ISortStrategy
{
    void Sort(List<int> data);
}

public class QuickSort : ISortStrategy { /*...*/ }
public class MergeSort : ISortStrategy { /*...*/ }

public class Sorter
{
    private ISortStrategy _strategy;

    public void SetStrategy(ISortStrategy strategy) => _strategy = strategy;
    public void Sort(List<int> data) => _strategy?.Sort(data);
}

Применение: Платежные системы, алгоритмы обработки данных

4. Архитектурные паттерны

4.1. Repository

Суть: Абстрагирует доступ к данным

public interface IRepository<T>
{
    T GetById(int id);
    void Add(T entity);
}

public class UserRepository : IRepository<User>
{
    public User GetById(int id) { /*...*/ }
    public void Add(User entity) { /*...*/ }
}

4.2. CQRS

Суть: Разделение операций чтения и записи

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand>
{
    public Task Handle(CreateUserCommand command) { /*...*/ }
}

5. Паттерны параллельного программирования

5.1. Producer-Consumer

Суть: Разделение процессов генерации и обработки данных

BlockingCollection<Item> _queue = new();

// Producer
Task.Run(() =>
{
    while (true)
        _queue.Add(GenerateItem());
});

// Consumer
Task.Run(() =>
{
    foreach (var item in _queue.GetConsumingEnumerable())
        ProcessItem(item);
});

Критерии выбора паттернов

  1. Проблема: Какую конкретную проблему решаем?
  2. Гибкость: Нужны ли изменения в будущем?
  3. Сложность: Оправдана ли сложность внедрения?
  4. Производительность: Есть ли ограничения?

Резюмируем:

паттерны - это проверенные решения распространенных проблем проектирования. Их правильное применение значительно улучшает качество кода, но слепое следование паттернам без понимания контекста может усложнить систему. Важно выбирать паттерны осознанно, исходя из конкретных требований проекта.