Паттерны проектирования в C# с примерами кода

Онлайн-тренажер Python для начинающих

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

Начать курс

Паттерны проектирования в C#: полное руководство с примерами

Паттерны проектирования (Design Patterns) — это проверенные решения типовых задач, возникающих при разработке программного обеспечения. В экосистеме .NET и C# знание паттернов особенно важно, так как многие из них встроены непосредственно в платформу (например, IDisposable для паттерна Dispose). В этой статье мы разберём три основные группы паттернов по классификации GoF (Gang of Four) с практическими примерами на C#.

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

Порождающие паттерны отвечают за создание объектов, делая систему независимой от способа их создания, композиции и представления.

Singleton (Одиночка)

Гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему. В C# часто используется для работы с логгерами, кэшем или конфигурацией.

public sealed class Logger
{
    private static readonly Lazy<Logger> _instance = 
        new Lazy<Logger>(() => new Logger());

    public static Logger Instance => _instance.Value;

    private Logger() { }

    public void Log(string message)
    {
        Console.WriteLine($"[{DateTime.Now}] {message}");
    }
}

// Использование
Logger.Instance.Log("Приложение запущено");

Factory Method (Фабричный метод)

Определяет интерфейс для создания объекта, но позволяет подклассам изменять тип создаваемого объекта. Отлично подходит для логики, которая должна быть расширяемой.

public interface ITransport
{
    void Deliver();
}

public class Truck : ITransport
{
    public void Deliver() => Console.WriteLine("Доставка по дороге");
}

public class Ship : ITransport
{
    public void Deliver() => Console.WriteLine("Доставка по морю");
}

public abstract class Logistics
{
    public abstract ITransport CreateTransport();

    public void PlanDelivery()
    {
        var transport = CreateTransport();
        transport.Deliver();
    }
}

public class RoadLogistics : Logistics
{
    public override ITransport CreateTransport() => new Truck();
}

public class SeaLogistics : Logistics
{
    public override ITransport CreateTransport() => new Ship();
}

// Использование
Logistics logistics = new RoadLogistics();
logistics.PlanDelivery(); // Доставка по дороге

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

Структурные паттерны определяют способы построения классов и объектов для формирования более крупных структур.

Adapter (Адаптер)

Преобразует интерфейс одного класса в другой интерфейс, ожидаемый клиентом. Часто применяется для интеграции со сторонними библиотеками или устаревшим кодом.

// Целевой интерфейс (ITarget)
public interface IXmlParser
{
    string ParseToXml(string data);
}

// Адаптируемый класс (Adaptee)
public class JsonParser
{
    public string ParseToJson(string data) 
    {
        return $"{{\"data\": \"{data}\"}}";
    }
}

// Адаптер
public class JsonToXmlAdapter : IXmlParser
{
    private readonly JsonParser _jsonParser;

    public JsonToXmlAdapter(JsonParser jsonParser)
    {
        _jsonParser = jsonParser;
    }

    public string ParseToXml(string data)
    {
        var json = _jsonParser.ParseToJson(data);
        // Простейшая конвертация JSON в XML
        return $"<data>{data}</data>";
    }
}

// Использование
var adapter = new JsonToXmlAdapter(new JsonParser());
string xml = adapter.ParseToXml("Hello");
Console.WriteLine(xml); // <data>Hello</data>

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

Динамически добавляет объекту новые обязанности. В C# этот паттерн часто реализуется через наследование или композицию.

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;

    public NotifierDecorator(INotifier notifier)
    {
        _notifier = notifier;
    }

    public virtual void Send(string message)
    {
        _notifier.Send(message);
    }
}

public class SmsDecorator : NotifierDecorator
{
    public SmsDecorator(INotifier notifier) : base(notifier) { }

    public override void Send(string message)
    {
        base.Send(message);
        Console.WriteLine($"SMS отправлено: {message}");
    }
}

// Использование
INotifier notifier = new EmailNotifier();
notifier = new SmsDecorator(notifier);
notifier.Send("Важное уведомление");
// Вывод:
// Email отправлен: Важное уведомление
// SMS отправлено: Важное уведомление

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

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

Observer (Наблюдатель)

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

public class Stock
{
    private decimal _price;
    public event EventHandler<decimal> PriceChanged;

    public decimal Price
    {
        get => _price;
        set
        {
            if (_price != value)
            {
                _price = value;
                PriceChanged?.Invoke(this, _price);
            }
        }
    }
}

public class Investor
{
    public string Name { get; set; }

    public void OnPriceChanged(object sender, decimal newPrice)
    {
        Console.WriteLine($"{Name} получил уведомление: новая цена {newPrice:C}");
    }
}

// Использование
var stock = new Stock();
var investor1 = new Investor { Name = "Иван" };
var investor2 = new Investor { Name = "Мария" };

stock.PriceChanged += investor1.OnPriceChanged;
stock.PriceChanged += investor2.OnPriceChanged;

stock.Price = 150.50m;
// Вывод:
// Иван получил уведомление: новая цена 150,50 ₽
// Мария получил уведомление: новая цена 150,50 ₽

Strategy (Стратегия)

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

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

public class BubbleSort : ISortStrategy
{
    public void Sort(List<int> list)
    {
        Console.WriteLine("Сортировка пузырьком...");
        list.Sort(); // упрощённая реализация
    }
}

public class QuickSort : ISortStrategy
{
    public void Sort(List<int> list)
    {
        Console.WriteLine("Быстрая сортировка...");
        list.Sort();
    }
}

public class SortedList
{
    private                

Блоги

Рекомендаций по книгам