Menu
Coddy logo textTech

Паттерн Factory

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

Паттерн «Фабрика» (Factory pattern) — это порождающий паттерн, который делегирует создание объектов отдельному методу или классу. Вместо того чтобы использовать new напрямую в коде, вы просите фабрику создать объекты за вас. Это централизует логику создания и делает ваш код более гибким.

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

// Без Фабрики — разрозненная логика создания
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

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

challenge icon

Задание

Легко

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

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

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

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

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

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

Например, если входные данные — push и Meeting in 5 minutes, результат должен быть:

Push: Meeting in 5 minutes

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

Шпаргалка

Паттерн Фабрика (Factory pattern) — это порождающий паттерн проектирования, который делегирует создание объектов отдельному методу или классу, централизуя логику создания и делая код более гибким.

Без фабрики создание объектов разбросано по коду и имеет сильную связанность:

// Без Фабрики — разрозненная логика создания
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();  // Opening PDF

Паттерн Фабрика упрощает добавление новых типов — изменения изолированы в фабрике, а не разбросаны по всей кодовой базе.

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

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Проверьте себя

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

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