Как увеличить новый тип и не нужно изменять фабричный класс? - PullRequest
0 голосов
/ 16 сентября 2018

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

Animal.java:

public interface Animal {
    void eat();
}

Dog.java:

public class Dog implements Animal {
    ...
    @Override
    public void eat(){
        System.out.println("eat bones");
    }
}

Cat.java

public class Cat implements Animal {
    ...
    @Override
    public void eat(){
        System.out.println("eat fish");
    }
}

Теперь яу меня есть интерфейс Animal и два класса Animal, тогда у меня есть моя фабрика:

public class AnimalFactory {
    public static final int Dog = 1;
    public static final int Cat = 2;

    public static Animal getAnimal(int type) {
        switch(type) {
           case Dog: return new Dog();
           case Cat: return new Cat();
           default: return null;
        }
    }
}

Это очень просто, но если у меня новый тип Mouse, я должен изменить свою фабрику, чтобы добавить случайутверждение типа case Mouse: return new Mouse.

Итак, есть ли способ увеличить новый тип и не нужно изменять мой фабричный класс?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

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

С Весной Собака может быть объявлена ​​как:

@Component
@Scope("prototype")
public class Dog extends Animal{..}

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

А со стороны клиента вы можете просто добавить экземпляр Animal, например:

@Autowired
private Dog dog;

Или с использованием явной фабрики Dog dog = ApplicationContext.getBean("dog");

0 голосов
/ 16 сентября 2018

в вашем случае ваш фабричный метод в настоящее время не имеет какой-либо сложной логики для определения того, какой класс должен быть создан и возвращен его объект - поэтому вместо передачи типа животных в качестве целочисленной константы вы также можете передать java.lang.Class<? extends Animal> animalClass в качестве метода используя параметр generics и создайте соответствующий экземпляр животного конкретного класса, используя отражение (посмотрите на Class.newInstance()) ... это избавит вас от необходимости писать дополнительный код каждый раз Вы добавляете новый тип животных ...

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

Class<? extends Animal> animalClass разрешает только экземпляры класса, передаваемые в ваш фабричный метод в качестве параметра, которые являются подклассами / интерфейсами-реализациями класса Animal.

public static Animal getAnimal(Class<? extends Animal> animalClass) throws Exception {
    return animalClass.newInstance(); 
    // >=JAVA9: return animalClass.getDeclaredConstructors().newInstance(); 
}

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

Animal animal = AnimalFactory.getAnimal(Dog.class);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...