Паттерн 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, а не во всех местах, где создаются документы. Такое разделение упрощает сопровождение и тестирование вашей кодовой базы.
Задание
ЛегкоДавайте создадим систему уведомлений с использованием шаблона 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"returnsEmailNotification"sms"returnsSmsNotification"push"returnsPushNotification
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 и вывести результат
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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#