Одной из возможностей будет использование enum. На простейшем уровне вы могли бы заменить константы, такие как Rose.NAME
, на значения перечисления и поддерживать внутреннее отображение между значениями перечисления и классами для создания экземпляра:
public enum Flowers {
ROSE(Rose.class),
OLEANDER(Oleander.class);
private final Class<? extends Flower> flowerClass;
Flowers(Class<? extends Flower> flowerClass) {
this.flowerClass = flowerClass;
}
public Flower getFlower() {
Flower flower = null;
try {
flower = flowerClass.newInstance();
} catch (InstantiationException e) {
// This should not happen
assert false;
} catch (IllegalAccessException e) {
// This should not happen
assert false;
}
return flower;
}
}
Поскольку классы классов цветов не имеют конструктора по умолчанию, Class.newInstance()
использовать нельзя, поэтому создание экземпляра класса с помощью отражения немного более громоздко (хотя и возможно). Альтернативой может быть использование Prototype для создания нового экземпляра цветка.
Это уже гарантирует, что вы всегда будете поддерживать соответствие между возможными названиями цветов и фактическими классами цветов в синхронизации. Когда вы добавляете новый класс цветка, вы должны создать новое значение перечисления, которое включает в себя отображение для создания новых экземпляров класса. Однако проблема с подходом enum заключается в том, что используемый вами экземпляр Garden
исправлен при запуске. (Если вы не передадите его в качестве параметра getFlower()
- но тогда есть риск потери согласованности, т. Е. Будет труднее обеспечить создание определенной группы цветов в определенном саду).
Если вы хотите быть еще более гибким, вы можете рассмотреть возможность использования Spring для перемещения всего отображения между именами и конкретными (bean) классами в файл конфигурации. Затем ваша фабрика просто загружает Spring ApplicationContext в фоновом режиме и использует определенное в нем отображение. Всякий раз, когда вы вводите новый подкласс цветка, вам просто нужно добавить новую строку в файл конфигурации. Опять же, однако, этот подход, в его самой простой форме, требует, чтобы вы исправили экземпляр компонента Garden
во время конфигурации.
Если вы хотите переключаться между разными садами во время выполнения и обеспечивать согласованность между садами и группами цветов, Фабрика, использующая внутреннюю карту имен для классов цветов, может быть лучшим выбором. Принимая во внимание, что само сопоставление может быть снова сохранено в конфигурации, но вы можете создавать экземпляры отдельных экземпляров фабрики с различными экземплярами Garden
во время выполнения.