Menu
Coddy logo textTech

Паттерн Factory

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

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

Рассмотрим систему уведомлений, которая может отправлять электронные письма, SMS или push-уведомления. Без фабрики вашему коду пришлось бы знать о каждом конкретном классе:

// Без фабрики — клиент должен знать все конкретные классы
Notification notification;
if (type.equals("email")) {
    notification = new EmailNotification();
} else if (type.equals("sms")) {
    notification = new SMSNotification();
}

С помощью паттерна Фабрика вы централизуете логику создания:

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;
    }
}

Теперь клиентский код стал чище и не зависит от конкретных классов:

Notification notification = NotificationFactory.create("email");
notification.send("Hello!");  // Вывод: Email: Hello!

Ключевое преимущество заключается в том, что добавление новых типов уведомлений требует только обновления фабрики — клиентский код остается неизменным. Это следует принципу программирования на уровне интерфейса, что делает вашу систему более гибкой и простой в расширении.

challenge icon

Задание

Легко

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

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

  • Shape.java: Определите интерфейс с именем Shape, который служит общим контрактом для всех фигур. Ваш интерфейс должен объявлять один метод draw(), который ничего не возвращает, но выводит информацию о рисуемой фигуре.
  • Shapes.java: Создайте три класса, реализующих ваш интерфейс Shape:

    Circle — его метод draw() должен выводить Drawing a Circle

    Rectangle — его метод draw() должен выводить Drawing a Rectangle

    Triangle — его метод draw() должен выводить Drawing a Triangle

  • ShapeFactory.java: Создайте класс фабрики, который управляет созданием фигур. Ваш ShapeFactory должен иметь статический метод createShape(String type), который возвращает Shape. В зависимости от параметра типа:
    • Если тип равен "circle", верните новый Circle
    • Если тип равен "rectangle", верните новый Rectangle
    • Если тип равен "triangle", верните новый Triangle
    • Для любого другого значения верните null
  • Main.java: Объедините вашу систему фабрик! Вы получите два входных значения: два типа фигур (обе строки).

    Для каждого входного значения используйте ShapeFactory, чтобы создать фигуру и сохранить ее в переменной типа Shape. Если фабрика возвращает валидную фигуру (не null), вызовите ее метод draw(). Если она возвращает null, выведите Unknown shape: [type], где [type] — это предоставленное входное значение.

    Обработайте оба входных значения по порядку, каждое на отдельной строке вывода.

Вы получите два входных значения по порядку: первый тип фигуры (String) и второй тип фигуры (String).

Обратите внимание, что ваш класс Main никогда не использует new Circle() или new Rectangle() напрямую — он знает только об интерфейсе Shape и просит фабрику создать объекты. В этом и заключается сила паттерна «Фабрика»: клиентский код отделен от конкретных классов!

Шпаргалка

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

Вместо того чтобы создавать экземпляры объектов напрямую с помощью new, вы используете фабричный метод:

// Без фабрики — клиент зависит от конкретных классов
Notification notification;
if (type.equals("email")) {
    notification = new EmailNotification();
} else if (type.equals("sms")) {
    notification = new SMSNotification();
}

С паттерном «Фабрика» определите общий интерфейс и конкретные реализации:

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;
    }
}

Клиентский код использует фабрику вместо прямого создания экземпляров:

Notification notification = NotificationFactory.create("email");
notification.send("Hello!");  // Вывод: Email: Hello!

Преимущества: Добавление новых типов требует обновления только фабрики — клиентский код остается неизменным. Это соответствует принципу программирования на уровне интерфейсов, что делает системы более гибкими и простыми в расширении.

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

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()
        // Если фигура null, выведите "Unknown shape: [type]"
        
        // TODO: Сделайте то же самое для второй фигуры
        
    }
}
quiz iconПроверьте себя

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

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