Паттерн Factory
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 66 из 87.
Factory Pattern — это порождающий шаблон проектирования, который делегирует создание объектов отдельному методу или классу. Вместо того чтобы напрямую использовать new в своём коде, вы просите фабрику создавать объекты за вас. Это особенно полезно, когда у вас есть несколько связанных классов, использующих общий интерфейс или родительский класс.
Рассмотрим систему notification, которая может отправлять электронные письма, SMS или push-уведомления. Без фабрики вашему коду пришлось бы знать о каждом concrete class:
// Без Factory — клиент должен знать все конкретные классы
Notification notification;
if (type.equals("email")) {
notification = new EmailNotification();
} else if (type.equals("sms")) {
notification = new SMSNotification();
}С помощью шаблона Factory вы централизуете эту логику создания:
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}
public class NotificationFactory {
public static Notification create(String type) {
if (type.equals("email")) {
return new EmailNotification();
} else if (type.equals("sms")) {
return new SMSNotification();
}
return null;
}
}Теперь код client стал чище и не зависит от concrete classes:
Notification notification = NotificationFactory.create("email");
notification.send("Hello!"); // Вывод: Email: Hello!Ключевое преимущество заключается в том, что для добавления новых типов уведомлений требуется обновить только фабрику: код client остаётся неизменным. Это соответствует принципу программирования на основе interface, делая вашу систему более гибкой и удобной для расширения.
Задание
ЛегкоДавайте создадим систему рисования фигур с использованием шаблона Factory! Вместо того чтобы создавать объекты фигур напрямую по всему коду, вы централизуете логику создания в фабрике, которая создаёт разные типы фигур на основе простого строкового идентификатора.
Вы организуете код в четырёх файлах:
Shape.java: Define интерфейс под названиемShape, который служит общим контрактом для всех фигур. Ваш интерфейс должен declare единственный methoddraw(), который ничего не возвращает, а выводит информацию о рисуемой фигуре.Shapes.java: Create три classes, которые implement ваш интерфейсShape:Circle— его methoddraw()должен выводитьDrawing a CircleRectangle— его methoddraw()должен выводитьDrawing a RectangleTriangle— его methoddraw()должен выводитьDrawing a TriangleShapeFactory.java: Create класс Factory, который отвечает за создание фигур. ВашShapeFactoryдолжен иметь статический methodcreateShape(String type), возвращающийShape. В зависимости от параметра type:- Если type equals
"circle", return новыйCircle - Если type equals
"rectangle", return новыйRectangle - Если type equals
"triangle", return новыйTriangle - Для любого другого значения return
null
- Если type equals
Main.java: Объедините вашу фабричную систему! Вы получите два входных значения: два типа фигур (оба String).Для каждого входного значения используйте ваш
ShapeFactory, чтобы create фигуру, и сохраните её в переменнойShape. Если Factory возвращает допустимую фигуру (не null), вызовите её methoddraw(). Если она возвращает null, выведитеUnknown shape: [type], где [type] — предоставленное входное значение.Обработайте оба входных значения по порядку, каждое в своей строке вывода.
Вы получите два входных значения по порядку: первый тип фигуры (String) и второй тип фигуры (String).
Обратите внимание, что ваш класс Main никогда не использует new Circle() или new Rectangle() напрямую. Он знает только об интерфейсе Shape и просит Factory create объекты. В этом заключается сила шаблона Factory: код client отделён от concrete classes!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Прочитать два типа фигур
String type1 = scanner.nextLine();
String type2 = scanner.nextLine();
// TODO: Используйте ShapeFactory для создания первой фигуры
// Если фигура не null, вызовите draw()
// If the shape is null, print "Unknown shape: [type]"
// TODO: Сделайте то же самое для второй фигуры
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»Потренируйтесь самостоятельно: Онлайн-компилятор Java