Menu
Coddy logo textTech

Паттерн Factory

Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy. Урок 53 из 70.

Паттерн Factory — это порождающий паттерн, который делегирует creation объектов отдельному method или class. Вместо того чтобы напрямую использовать new в своём коде, вы просите factory create объекты за вас. Это централизует creation logic и делает ваш код более гибким.

Рассмотрим сценарий, в котором вам нужно создавать разные типы документов. Без factory ваш код становится тесно связанным с конкретными классами:

// Без Factory - разбросанная логика создания
IDocument doc;
if (type == "pdf")
    doc = new PdfDocument();
else if (type == "word")
    doc = new WordDocument();

Фабрика инкапсулирует эту логику принятия решений в одном месте:

public interface IDocument
{
    void Open();
}

public class PdfDocument : IDocument
{
    public void Open() => Console.WriteLine("Opening PDF");
}

public class WordDocument : IDocument
{
    public void Open() => Console.WriteLine("Opening Word");
}

public class DocumentFactory
{
    public IDocument Create(string type)
    {
        return type switch
        {
            "pdf" => new PdfDocument(),
            "word" => new WordDocument(),
            _ => throw new ArgumentException("Unknown type")
        };
    }
}

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

var factory = new DocumentFactory();
IDocument doc = factory.Create("pdf");
doc.Open();  // Открытие PDF

Паттерн Factory особенно полезен, когда позже нужно добавить новые типы. Добавление SpreadsheetDocument требует изменений только в factory, а не во всех местах, где создаются документы. Такое разделение упрощает сопровождение и тестирование вашей кодовой базы.

challenge icon

Задание

Легко

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

Вы организуете код в трёх файлах:

  • Notification.cs: Define интерфейс INotification в пространстве имён Notifications с единственным методом Send(string message), который returns строку. Затем создайте три класса, реализующих этот интерфейс:
    • EmailNotification — returns "Email: {message}"
    • SmsNotification — returns "SMS: {message}"
    • PushNotification — returns "Push: {message}"
  • NotificationFactory.cs: Create класс NotificationFactory в том же пространстве имён с методом Create(string type), который returns соответствующий INotification на основе строки type:
    • "email" returns EmailNotification
    • "sms" returns SmsNotification
    • "push" returns PushNotification
    Для любого нераспознанного type return EmailNotification по умолчанию.
  • Program.cs: Объедините всё, создав instance factory и используя его для создания уведомлений на основе входных данных. factory обрабатывает всю логику выбора того, какой конкретный класс создать.

Вы получите два входных значения:

  • Тип уведомления (например, sms)
  • Сообщение для отправки (например, Your order has shipped)

Используйте factory, чтобы создать соответствующий тип уведомления, затем вызовите его метод Send с сообщением и выведите result.

Например, если входными данными являются push и Meeting in 5 minutes, output должен быть таким:

Push: Meeting in 5 minutes

Обратите внимание: ваш основной код никогда не использует new EmailNotification() или что-либо подобное — он просто запрашивает у factory то, что ему нужно. Если позже вы добавите SlackNotification, вам потребуется обновить только factory, а не каждое место, создающее уведомления!

Попробуйте сами

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // Прочитать ввод
        string type = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Создать экземпляр NotificationFactory

        // TODO: Использовать фабрику для создания соответствующего уведомления

        // TODO: Вызвать метод Send и вывести результат
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C#