Посмотрите на этот Java-псевдокод фабрики и объясните, какие антипаттерны он содержит и как можно рефакторить его с помощью паттернов проектирования (каких именно): class WidgetFactory { Widget create(String type) { switch(type) { case "A": return new AWidget(); case "B": return new BWidget(); /* много типов */ } } }

10 Окт в 13:32
3 +1
0
Ответы
1

Код, который вы привели, — классический пример «простого фабричного» метода с switch/if-else по строке. Ниже — какие конкретно антипаттерны и принципы нарушаются и как это рефакторить спримерамииуказаниями,какиепаттерныиспользоватьипочемус примерами и указаниями, какие паттерны использовать и почемуспримерамииуказаниями,какиепаттерныиспользоватьипочему.

Что не так антипаттерны/нарушенияпринциповантипаттерны / нарушения принциповантипаттерны/нарушенияпринципов

Большой switch/chain of conditionals
Технически — «Conditional Complexity» / «Switch‑case smell». С ростом числа типов код раздувается.Нарушение Open‑Closed Principle OCPOCPOCP Чтобы добавить новый тип, нужно менять метод create, т.е. модифицировать существующий код.Примитивная одержимость PrimitiveObsessionPrimitive ObsessionPrimitiveObsession Использование строки "type" как ключа ведёт к хрупкости: опечатки, отсутствие проверок, нет автокомплита.Жёсткая связность tightcouplingtight couplingtightcoupling Фабрика явно создаёт конкретные классы; потребители не могут подменить реализации без изменения фабрики.Трудности с передачей зависимостей
Если создание AWidget/BWidget требует зависимостей, фабрика превращается в «канистра» для их передачи и ещё сильнее разрастается.

Как можно рефакторить паттерныиподходыпаттерны и подходыпаттерныиподходы

1) Registry + Supplier / Map of creators рекомендуемыйпростойвариантрекомендуемый простой вариантрекомендуемыйпростойвариант

Идея: регистрировать фабричные функции Supplier,FactoryFunctionSupplier, FactoryFunctionSupplier,FactoryFunction в map по ключу. Добавление нового типа — регистрация, без изменения кода фабрики.Плюсы: простой, гибкий, хорошо сочетается с DI. Позволяет ленивая/динамическая регистрация плагиныплагиныплагины.Минусы: ключи всё ещё могут быть строки решаетсяenumилиClassрешается enum или ClassрешаетсяenumилиClass.

Пример:

class WidgetFactory {
private final Map<String, Supplier<Widget>> registry = new HashMap<>;
public void register(String key, Supplier<Widget> creator) {
registry.putkey,creatorkey, creatorkey,creator;
}
public Widget createStringkeyString keyStringkey {
Supplier<Widget> s = registry.getkeykeykey;
if s==nulls == nulls==null throw new IllegalArgumentException"Unknownwidget:"+key"Unknown widget: " + key"Unknownwidget:"+key;
return s.get;
}
}
// регистрация
factory.register"A",AWidget::new"A", AWidget::new"A",AWidget::new;
factory.register"B",BWidget::new"B", BWidget::new"B",BWidget::new;

2) Factory Method GoFGoFGoF

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

Пример:

abstract class WidgetFactory {
abstract Widget create;
}
class AWidgetFactory extends WidgetFactory {
Widget create { return new AWidget; }
}

3) Abstract Factory GoFGoFGoF

Идея: если у вас семейства взаимосвязанных виджетов A‑семейство,B‑семействоA‑семейство, B‑семействоAсемейство,Bсемейство, Abstract Factory создаёт набор связанных продуктов.Применение: когда нужны совместимые продукты, например AButton + AWindow.Плюсы: инкапсулирует группу фабрик, удобно для смены «тем».

4) Enum с полиморфизмом

Если набор типов фиксирован и известен во время компиляции, enum может инкапсулировать создание.Плюсы: типобезопасность, один файл, лёгкая замена строк.
enum WidgetType {
A { Widget create { return new AWidget; } },
B { Widget create { return new BWidget; } };
abstract Widget create;
}

5) Прототип PrototypePrototypePrototype

Если экземпляры сложны для создания, но можно клонировать готовый объект: храните образец и клонируйте.Полезно при дорогом создании.

6) Использование DI-контейнера / ServiceLoader

Зарегистрировать реализации в контейнере Spring,GuiceSpring, GuiceSpring,Guice или использовать ServiceLoader для плагинов.DI решает проблему зависимостей и регистрации автоматически.

7) Рефлексия / class name mapping менеепредпочтительноменее предпочтительноменеепредпочтительно

По имени класса создавать новый экземпляр через reflection. Работает, но теряется типобезопасность и появляется риск ошибок в рантайме.

Выбор подхода — рекомендации

Если количество типов небольшое и фиксированное — enum с полиморфизмом или Factory Method подойдёт.Если типов много и они могут добавляться динамически плагиныплагиныплагины — Registry (Map<String, Supplier>) или DI‑контейнер/ServiceLoader.Если у вас семейства совместимых продуктов — Abstract Factory.Если создание продукта требует сложной конфигурации — Builder или Prototype.

Дополнительно: как учесть зависимости

Не делайте фабрику «новым конструктором» для всех зависимостей. Лучше:
Передавайте необходимые зависимости в регистратор/поставщик SupplierсзамыканиемSupplier с замыканиемSupplierсзамыканием, либоИспользуйте DI для инъекции фабрик/поставщиков.

Пример с DI‑дружественным registry, учитывающий зависимости:

factory.register("A", () -> new AWidget(dependency1, dependency2));

Короткое резюме

Текущий код: нарушение OCP, switch‑case антипаттерн, primitive obsession, tight coupling.Быстрые правки: заменить switch на map registry с Supplier; или использовать enum для фиксированного набора.Более архитектурные: Factory Method, Abstract Factory, Prototype, DI/ServiceLoader в зависимости от требований.

Если хотите, могу:

Переписать ваш класс конкретно под ваш проект показатьреализациюRegistry+DI,илиenum,илиAbstractFactoryпоказать реализацию Registry + DI, или enum, или Abstract FactoryпоказатьреализациюRegistry+DI,илиenum,илиAbstractFactory — пришлите требования числотипов,будутлидобавлятьсяплагины,нужнылизависимостиувиджетовчисло типов, будут ли добавляться плагины, нужны ли зависимости у виджетовчислотипов,будутлидобавлятьсяплагины,нужнылизависимостиувиджетов.
10 Окт в 14:10
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир