В чем главная цель Factory Method (фабричного метода)?

Рейтинг: -1Ответов: 1Опубликовано: 16.04.2023

Цель фабричного метода я вижу в том что клиент передает объект с фабричным методом без создания объекта который создает фабричный метод, таким образом мы не создаем если не надо и с другой стороны можем себе наклепать сколько угодно объектов.

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

Если там есть какие-то поля объекта/класса которые задаются до передачи, вызываются какие-то функции как в декораторе, то понятно зачем нужен паттерн, а здесь не совсем.

Я правильно понимаю что это основная выгода от создания фабричного метода? Потому что иначе я могу просто использовать new. Ещё приходит на ум мебель и её стили, допустим все настолько разное что паттерн Мост не вариант. Тогда я могу отнаследоваться от просто мебели и передать мебель нужного мне типа, а там когда надо создастся сколько надо мебели с нужным стилем.

В интернете вижу примеры как этого

public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;
        switch (type) {
            case AMERICANO:
                coffee = new ItalianStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new ItalianStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new ItalianStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new ItalianStyleCaffeLatte();
                break;
        }
        return coffee;
    }
}

public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new AmericanStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new AmericanStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new AmericanStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new AmericanStyleCaffeLatte();
                break;
        }

        return coffee;
    }

}

public class Main {
    public static void main(String[] args) {
        /*
            Закажем капучино в итальянском стиле:
            1. Создадим фабрику для приготовления итальянского кофе
            2. Создадим новую кофейню, передав ей в конструкторе фабрику итальянского кофе
            3. Закажем наш кофе
         */
        SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
        CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
        italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);


         /*
            Закажем капучино в американском стиле
            1. Создадим фабрику для приготовления американского кофе
            2. Создадим новую кофейню, передав ей в конструкторе фабрику американского кофе
            3. Закажем наш кофе
         */
        SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
        CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
        americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
    }
}

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

Ответы

▲ 1Принят

В моем понимании весь смысл фабрики сводится к инкапсуляции логики создания объектов. Этому можно найти массу применений, но пожалуй самое важное из них это реализация инверсии зависимостей. Просто сейчас за нас грязную работу проделывают DI-фреймворки.

Попробую привести банальный пример. Представьте, что вам надо написать кучу бизнес-логики, завязанной на отправку SMS, при этом вы скорее всего изучили предметную область и узнали, что смс-шлюзы бывают разные, поэтому сначала завели интерфейс SmsService, а уже потом сделали имплементацию под конкретного вендора - SomeVendorSmsService. Так вот, вы конечно можете ссылаться в бизнес-логике напрямую на наследника, но скорее всего захотите ссылаться только на интерфейс. Зачем? Чтобы в случае чего легко переехать на другого вендора, либо вообще использовать ту или иную реализацию в зависимости от обстоятельств (регион, оператор и т.п) А как вы будете этого достигать если у вас нет DI-фреймворка? Ну наверное вряд ли вы захотите дублировать всю эту логику при каждой необходимости просто отправить SMS. Тут то и нужна фабрика.