Шаблон создания: фабричный метод

Dec 04 2022
В этой статье обсуждается, как производные классы могут использовать свои конструкторы для создания соответствующих объектов. Что это? Фабрика программного обеспечения создает объекты, а фабрика, производящая товары реального мира, производит товары.

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

Что это?

Фабрика программного обеспечения создает объекты, а фабрика, производящая товары реального мира, производит товары. Например, создание объектов в Java обычно происходит так:

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

Фабричный метод — это шаблон проектирования класса, который предоставляет интерфейс для создания объектов, но позволяет подклассам решать, экземпляр какого класса создавать.

Диаграмма классов

Диаграмма классов включает в себя следующие элементы:

  • Товар
  • Бетонный продукт
  • Создатель
  • Бетон Творец

Продолжая наш пример с самолетом, предположим, что мы пытаемся смоделировать истребитель F-16. Код клиента должен создать объект двигателя для этого самолета и запустить его. Наивная реализация для этого класса будет выглядеть примерно так:

В приведенном выше коде мы обязались использовать конкретную реализацию класса F16. Что, если компания предложит более новые версии самолета, и мы обязаны представить их в нашей программе? Это означало бы изменение клиентского кода, в котором мы создаем экземпляр F16. Один из выходов — инкапсулировать создание объекта в другой объект, отвечающий исключительно за создание запрошенных вариантов F-16. Для начала предположим, что мы хотим представить варианты A и B F16; наш код может выглядеть так:

Простая фабрика — это простая идиома программирования, которая не создает объект фабрики. Метод make можно сделать статическим, чтобы избежать создания ненужного объекта. Однако, поскольку статические методы нельзя переопределить в подклассах, мы не сможем использовать эту простую фабрику в качестве основы для абстрактной иерархии классов.

Тем не менее, мы хотим сохранить создание частей объекта F16 в одном классе и по-прежнему иметь возможность вводить новые варианты F16 по мере их появления. В этом случае мы могли бы создать подкласс F16 и делегировать создание правильного объекта варианта F16 подклассу, обрабатывающему этот вариант. Именно так работает паттерн фабричный метод! Здесь фабричным методом является makeF16(), который создаст новый вариант F16 при вызове. Двигаясь вперед, мы вводим два подкласса, например

Мы создали подклассы и специализировали объект движка, используя наследование. Фабричный метод может предоставлять или не предоставлять стандартную или общую реализацию; однако мы все равно можем переопределить его в подклассах, чтобы специализировать или изменить продукт. В нашем примере есть два варианта модели, каждая с другим двигателем, но с одинаковой кабиной. Клиентский код теперь может использовать более новые модели следующим образом:

Обратите внимание, что шаблон проектирования фабричных методов возвращает абстрактный тип, либо интерфейс Java, либо абстрактный класс Java. Суперкласс, в нашем случае F16, не знает, какой именно вид F16 был возвращен методом makeF16(). Как правило, метод create является либо абстрактным, либо поставляется с реализацией по умолчанию, вызываемой другими методами суперкласса. Таким образом, подклассы должны создавать определенные виды объектов.

Различия с простой/статической фабрикой

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

Другие примеры

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

Java API предоставляет несколько фабричных методов:

java.util.Calendar.getInstance()

java.util.ResourceBundle.getBundle()

java.text.NumberFormat.getInstance()

Предостережения

  • Шаблон может привести к тому, что будет слишком много подклассов с незначительными различиями между ними.
  • Если подкласс добавляет функциональность суперклассу, он не может использовать новые методы, пока не приведёт объект к его конкретному типу. К сожалению, Downcasting может дать сбой во время выполнения.