Паттерн Factory
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy. Урок 53 из 70.
Фабричный паттерн — это порождающий паттерн, который делегирует создание объектов отдельному методу или классу. Вместо того чтобы напрямую использовать new в своём коде, вы просите фабрику создавать объекты за вас. Это централизует логику создания и делает ваш код более гибким.
Рассмотрим сценарий, в котором вам нужно создавать разные типы документов. Без фабрики ваш код оказывается тесно связан с конкретными классами:
// Без 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)
{
switch (type)
{
case "pdf":
return new PdfDocument();
case "word":
return new WordDocument();
default:
throw new ArgumentException("Unknown type");
}
}
}Теперь клиентский код просто запрашивает то, что ему нужно, не зная конкретных классов:
var factory = new DocumentFactory();
IDocument doc = factory.Create("pdf");
doc.Open(); // Открытие PDFПаттерн «Фабрика» особенно полезен, когда позже нужно добавлять новые типы. Добавление SpreadsheetDocument требует изменений только в фабрике, а не во всех местах, где создаются документы. Такое разделение упрощает поддержку и тестирование кодовой базы.
Задание
ЛегкоДавайте создадим систему уведомлений с использованием паттерна «Фабрика». Вместо того чтобы напрямую создавать разные типы уведомлений по всему коду, вы централизуете логику создания в классе-фабрике, который решает, какое уведомление создать, на основе простого строкового идентификатора.
Вы организуете код в трёх файлах:
Notification.cs: Определите интерфейсINotificationв пространстве имёнNotificationsс единственным методомSend(string message), который возвращает строку. Затем создайте три класса, реализующих этот интерфейс:EmailNotification— возвращает"Email: {message}"SmsNotification— возвращает"SMS: {message}"PushNotification— возвращает"Push: {message}"
NotificationFactory.cs: Создайте классNotificationFactoryв том же пространстве имён с методомCreate(string type), который возвращает соответствующийINotificationв зависимости от строкового значения type:"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, вам потребуется обновить только фабрику, а не каждое место, где создаются уведомления!
Попробуйте сами
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 и вывести результат
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методовПотренируйтесь самостоятельно: Онлайн-компилятор C#