Menu
Coddy logo textTech

Паттерн Builder

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

Builder Pattern — это порождающий шаблон проектирования, который решает распространённую проблему: создание сложных объектов с множеством необязательных параметров. Вместо создания нескольких конструкторов или передачи null для неиспользуемых параметров Builder позволяет создавать объекты пошагово.

Рассмотрим создание объекта User с обязательными полями (name, email) и необязательными (age, phone, address). Без Builder вам пришлось бы использовать телескопические конструкторы или громоздкий конструктор с множеством параметров. Паттерн Builder предлагает более чистый подход:

public class User {
    private final String name;    // обязательный
    private final String email;   // обязательный
    private final int age;        // необязательный
    private final String phone;   // необязательный
    
    private User(UserBuilder builder) {
        this.name = builder.name;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
    }
    
    public static class UserBuilder {
        private final String name;
        private final String email;
        private int age;
        private String phone;
        
        public UserBuilder(String name, String email) {
            this.name = name;
            this.email = email;
        }
        
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

Методы Builder возвращают this, обеспечивая цепочку вызовов методов: плавный и удобный для чтения способ создавать объекты:

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

Обратите внимание, что User constructor является private: объекты можно создавать только через Builder. Этот паттерн особенно полезен, когда у объектов много optional fields, поскольку он делает ваш код более читаемым и менее подверженным ошибкам, чем длинные списки parameter.

challenge icon

Задание

Легко

Давайте создадим систему заказа пиццы с использованием шаблона Builder! Вместо работы с constructor, который принимает десятки parameter для всех возможных начинок и опций, вы создадите fluent builder, благодаря которому настройка пиццы будет простой и понятной.

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

  • Pizza.java: Создайте Pizza class, который использует шаблон Builder для создания объектов. В вашей пицце должны быть следующие fields:

    size (String) — обязательное поле, обозначает размер пиццы

    cheese (boolean) — необязательное поле, по умолчанию имеет значение false

    pepperoni (boolean) — необязательное поле, по умолчанию имеет значение false

    mushrooms (boolean) — необязательное поле, по умолчанию имеет значение false

    constructor Pizza должен быть private и принимать только PizzaBuilder в качестве parameter, копируя все значения из builder в fields пиццы.

    Добавьте method getDescription(), который возвращает string в следующем формате: [size] Pizza with: [toppings], где toppings — это разделённый запятыми список toppings, имеющих значение true (Cheese, Pepperoni, Mushrooms). Если toppings не выбраны, часть с toppings должна содержать только no toppings.

    Создайте static inner class PizzaBuilder, содержащий:

    • constructor, принимающий обязательный parameter size
    • methods cheese(), pepperoni() и mushrooms(), каждый из которых устанавливает соответствующее boolean-значение в true и возвращает this для цепочки вызовов
    • method build(), который возвращает новую Pizza
  • Main.java: Продемонстрируйте работу builder для пиццы! Вы получите четыре inputs: размер пиццы (String) и три значения yes/no (Strings), указывающие, нужно ли соответственно добавить cheese, pepperoni и mushrooms.

    Создайте PizzaBuilder с указанным размером. Затем, основываясь на каждом input yes/no, вызовите в цепочке соответствующие methods для toppings. Если input равен "yes", вызовите method этой topping; если "no", пропустите его. Наконец, вызовите build(), чтобы создать пиццу.

    Выведите результат вызова getDescription() для созданной пиццы.

Вы получите четыре inputs по порядку: size (String), add cheese (String: "yes" или "no"), add pepperoni (String: "yes" или "no"), add mushrooms (String: "yes" или "no").

Например, для inputs Large, yes, no, yes результатом будет: Large Pizza with: Cheese, Mushrooms

Обратите внимание, как шаблон Builder позволяет создавать пиццы с любой комбинацией toppings без необходимости создавать отдельные constructors для каждого варианта!

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

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Считать входные данные
        String size = scanner.nextLine();
        String addCheese = scanner.nextLine();
        String addPepperoni = scanner.nextLine();
        String addMushrooms = scanner.nextLine();
        
        // TODO: Создать PizzaBuilder с заданным размером
        // TODO: Вызвать методы топпингов цепочкой на основе вводов yes/no
        // TODO: Собрать пиццу и вывести её описание
        
    }
}
quiz iconПроверьте себя

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

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

Потренируйтесь самостоятельно: Онлайн-компилятор Java