как избежать каскадирования операторов if\case в фабричном классе

Я должен создать объект на основе конкретной ситуации. Я читал, что решением может быть Factory Pattern, но в моем случае у него много недостатков.

Например: у меня есть приложение, которое управляет животными. В какой-то момент клиент дает мне список животных, которых нужно создать. Решение с использованием фабричного шаблона должно быть:

//PRODUCTS
public interface  Animal {
    String getCall();
}

public class Dog implements Animal {
    public String getCall() {
        return "Bau";
    }
}

public class Cat implements Animal {
    public String getCall() {
        return "Miao";
    }
}
public class Cow {...}
public class Rooster{...}

public enum AnimalEnum {
    Cat, Dog, Cow, Rooster
}



//FACTORY
public class AnimalFactory {
    public Animal getAnimal (AnimalEnum type){
        Animal retval = null;
        switch (type){
            case Cat:
                retval = new Cat();
                break;
            case Dog:
                retval = new Dog();
                break;
            case Cow:[...]
            case Rooster[...]

        }
        return retval;
    }
}

На мой взгляд, это запах кода. Проблема в кейсе-выписке, которую я должен написать, чтобы проверить, какое животное хочет клиент. Кроме того, если в будущем я захочу создать новый объект «Тигр», мне придется изменить все фабричные классы.

Мой вопрос: есть ли способ избежать этой ситуации? Есть ли шаблон, который позволяет мне создавать объект на основе другого параметра без такого «каскадного if\case-of»?

Я думал, использовать шаблон команды, но в конце у меня все еще есть такая ситуация.


person ale666    schedule 26.10.2019    source источник
comment
Это не запах кода, и так работает фабричный паттерн. Альтернативой этому является то, что остальная часть вашего кода должна будет беспокоиться о том, какой конкретный вид животных используется, и это масштабируется до гораздо менее поддерживаемого кода, чем то, что у вас есть в настоящее время.   -  person Tim Biegeleisen    schedule 26.10.2019


Ответы (1)


Понятие «запах кода» и его противоположность, «чистый код», восходит к Мартину Фаулеру и Роберту Мартину, см. этот пост для получения информации о нюансах обонятельного, гигиенического и моральное сравнение в области разработки программного обеспечения.

Что касается вопроса, то ваше представление о том, что такое переключение перечисления отвратительно, согласуется с Мартином Фаулером в оригинальном издании "Рефакторинг: улучшение дизайна существующего кода", но он отозвал его в выпуск 2015 года. По этому поводу нет единого мнения, в том числе среди нескольких участников, набравших 100 000 репутаций, например. @tim-biegeleisen заявляет, что вони нет, @mark-seemann настаивает на том, что есть, также после 2015 года, и обязательно так, пока существует Вселенная, согласно его склонности.

Что касается недовольства, которое вы испытываете по поводу этого конкретного фрагмента кода, вы можете переместить создание экземпляра в сам Enum, таким образом избегая оператора switch, а также не забывая добавлять дополнительные ветки switch при расширении перечисления.

public enum AnimalEnum {
    Cat(Cat::new), 
    Dog(Dog::new), 
    Cow(Cow::new), 
    Rooster(Rooster::new);

    private final Supplier<Animal> createAnimal;

    public Animal createInstance() {
        return createAnimal.get();
    }

    AnimalEnum(Supplier<Animal> factory) {
        this.createAnimal = factory;
    }
}

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

person Nikolai Dmitriev    schedule 26.10.2019