Jump to content

Фабрика (объектно-ориентированное программирование)

(Перенаправлено из шаблона Factory )
Фабричный метод в LePUS3

В объектно-ориентированном программировании фабрика это объект для создания других объектов ; формально это функция или метод , возвращающий объекты различного прототипа или класса. [ 1 ] из вызова какого-либо метода, который считается «новым». [ а ] В более широком смысле подпрограмма, возвращающая «новый» объект, может называться «фабрикой», как в фабричном методе или фабричной функции . Фабричный шаблон является основой для ряда связанных шаблонов проектирования программного обеспечения .

Мотивация

[ редактировать ]

В программировании на основе классов фабрика — это абстракция конструктора класса , тогда как в программировании на основе прототипов фабрика — это абстракция объекта-прототипа. Конструктор является конкретным в том смысле, что он создает объекты как экземпляры одного класса и с помощью указанного процесса (создание экземпляра класса), в то время как фабрика может создавать объекты путем создания экземпляров различных классов или с помощью других схем размещения, таких как пул объектов . Объект-прототип является конкретным в том смысле, что он используется для создания объектов путем клонирования , в то время как фабрика может создавать объекты путем клонирования различных прототипов или с помощью других схем распределения.

Фабрика может быть реализована различными способами. Чаще всего он реализуется как метод, и в этом случае его называют фабричным методом . Иногда она реализуется как функция, и в этом случае ее называют фабричной функцией . В некоторых языках конструкторы сами являются фабриками. Однако в большинстве языков это не так, и конструкторы вызываются идиоматическим для языка способом, например, с помощью ключевого слова new, тогда как фабрика не имеет специального статуса и вызывается посредством обычного вызова метода или функции. В этих языках фабрика — это абстракция конструктора, но не его строгое обобщение, поскольку конструкторы сами по себе не являются фабриками.

Терминология

[ редактировать ]

Терминология различается в зависимости от того, является ли сама концепция фабрики шаблоном проектирования — в шаблонах проектирования нет «шаблона фабрики», а вместо этого есть два шаблона ( шаблон фабричного метода и абстрактный шаблон фабрики ), которые используют фабрики. Некоторые источники называют эту концепцию фабричным шаблоном . [ 2 ] [ 3 ] в то время как другие считают саму концепцию идиомой программирования , [ 4 ] сохранение термина «фабричный шаблон» или «фабричные шаблоны» для более сложных шаблонов, использующих фабрики, чаще всего шаблон фабричного метода; в этом контексте концепцию фабрики можно назвать простой фабрикой. [ 4 ] В других контекстах, особенно в языке Python, используется сама «фабрика», как в этой статье. [ 5 ] В более широком смысле, «фабрика» может применяться не только к объекту, который возвращает объекты из вызова какого-либо метода, но и к подпрограмме , которая возвращает объекты, как в фабричной функции (даже если функции не являются объектами) или фабричном методе. [ 6 ] Поскольку во многих языках фабрики вызываются путем вызова метода, общую концепцию фабрики часто путают с конкретным шаблоном проектирования шаблона фабричного метода .

Использовать

[ редактировать ]

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

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

С технической точки зрения, в языках, где фабрики обобщают конструкторы, фабрики обычно можно использовать везде, где только могут быть конструкторы. [ с ] это означает, что интерфейсы, которые принимают конструктор, также могут принимать фабрику — обычно нужно только что-то, что создает объект, а не указывать класс и экземпляр.

Например, в Python функция collections.defaultdict сорт [ 7 ] имеет конструктор, который создает объект типа defaultdict[ д ] чьи значения по умолчанию создаются путем вызова фабрики. Фабрика передается в качестве аргумента конструктору и сама может быть конструктором или любой вещью, которая ведет себя как конструктор – вызываемый объект , который возвращает объект, т. е. фабрику. Например, используя list конструктор для списков:

# collections.defaultdict([default_factory[, ...]])
d = defaultdict(list)

Создание объекта

[ редактировать ]

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

Простейшим примером фабрики является простая фабричная функция, которая просто вызывает конструктор и возвращает результат. В Python фабричная функция f который создает экземпляр класса A может быть реализован как:

def f():
    return A()

Простая фабричная функция, реализующая шаблон Singleton:

def f():
    if f.obj is None:
        f.obj = A()
    return f.obj

f.obj = None

Это создаст объект при первом вызове и в дальнейшем всегда будет возвращать один и тот же объект.

Синтаксис

[ редактировать ]

Фабрики могут вызываться различными способами, чаще всего вызовом метода ( фабричный метод ), иногда путем вызова как функции, если фабрика является вызываемым объектом ( фабричная функция ). В некоторых языках конструкторы и фабрики имеют одинаковый синтаксис, тогда как в других конструкторы имеют специальный синтаксис. В языках, где конструкторы и фабрики имеют одинаковый синтаксис, например Python, Perl, Ruby, Object Pascal и F#, [ и ] конструкторы могут быть прозрачно заменены фабриками. В языках, где они различаются, их надо различать в интерфейсах, а переключение между конструкторами и фабриками требует изменения вызовов.

Семантика

[ редактировать ]

В языках, где объекты выделяются динамически , например в Java или Python, фабрики семантически эквивалентны конструкторам. Однако в таких языках, как C++, которые позволяют статически выделять некоторые объекты, фабрики отличаются от конструкторов для статически выделенных классов, поскольку для последних выделение памяти может определяться во время компиляции, тогда как выделение возвращаемых значений фабрик должно определяться во время компиляции. время выполнения. Если конструктор может быть передан в качестве аргумента функции, то вызов конструктора и выделение возвращаемого значения должны выполняться динамически во время выполнения и, таким образом, иметь семантику, аналогичную или идентичную вызову фабрики.

Шаблоны проектирования

[ редактировать ]

Фабрики используются в различных шаблонах проектирования , особенно в шаблонах создания, таких как библиотека объектов шаблонов проектирования . Для их реализации на многих языках были разработаны конкретные рецепты. Например, несколько « шаблонов GoF », таких как « шаблон фабричного метода », « Builder » или даже « Singleton », являются реализациями этой концепции. Вместо этого « абстрактный шаблон фабрики » представляет собой метод создания коллекций фабрик.

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

Приложения

[ редактировать ]

Фабричные объекты часто встречаются в наборах инструментов и платформах , где библиотечный код должен создавать объекты типов, которые могут быть разделены на подклассы приложениями, использующими эту платформу. Они также используются в разработке через тестирование , чтобы позволить тестировать классы. [ 8 ]

Фабрики определяют фактический конкретный тип объекта создаваемого , и именно здесь объект фактически создается. Поскольку фабрика возвращает объекту только абстрактный интерфейс, клиентский код не знает (и не обременен) фактическим конкретным типом только что созданного объекта. Однако тип конкретного объекта известен абстрактной фабрике. В частности, это означает:

  • Клиентский код ничего не знает о конкретном типе , и ему не нужно включать какие-либо заголовочные файлы или классов, объявления относящиеся к конкретному типу. Клиентский код имеет дело только с абстрактным типом. Объекты конкретного типа действительно создаются фабрикой, но клиентский код обращается к таким объектам только через их абстрактный интерфейс .
  • Добавление новых конкретных типов осуществляется путем изменения клиентского кода для использования другой фабрики, причем такая модификация обычно представляет собой одну строку в одном файле. Это значительно проще, чем модифицировать клиентский код для создания экземпляра нового типа, что потребует изменения каждого места в коде, где создается новый объект.

Применимость

[ редактировать ]

Фабрики можно использовать, когда:

  1. Создание объекта делает повторное использование невозможным без значительного дублирования кода.
  2. Для создания объекта требуется доступ к информации или ресурсам, которые не должны содержаться в составном классе.
  3. Управление временем существования созданных объектов должно быть централизованным, чтобы обеспечить согласованное поведение в приложении.

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

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

Фабричные методы используются в разработке через тестирование , чтобы позволить тестировать классы. [ 9 ] Если такой класс Foo создает еще один объект Dangerous который не может быть подвергнут автоматизированному модульному тестированию (возможно, он взаимодействует с рабочей базой данных, которая не всегда доступна), то создание Dangerous объекты помещаются в метод виртуальной фабрики createDangerous в классе Foo. Для тестирования, TestFoo (подкласс Foo) затем создается с помощью метода виртуальной фабрики createDangerous переопределено для создания и возврата FakeDangerous, поддельный объект . Модульные тесты затем используют TestFoo для проверки работоспособности Foo не подвергаясь побочному эффекту от использования настоящего Dangerous объект.

Преимущества и варианты

[ редактировать ]

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

Описательные имена

[ редактировать ]

Фабричный метод имеет отдельное имя. Во многих объектно-ориентированных языках конструкторы должны иметь то же имя, что и класс, в котором они находятся, что может привести к неоднозначности, если существует более одного способа создания объекта (см. Перегрузка ). Фабричные методы не имеют такого ограничения и могут иметь описательные имена; их иногда называют альтернативными конструкторами . Например, когда комплексные числа создаются из двух действительных чисел, действительные числа можно интерпретировать как декартовы или полярные координаты, но при использовании фабричных методов смысл становится ясен, как показано в следующем примере на C#.

public class Complex
{
    public double _real;
    public double _imaginary;

    public static Complex FromCartesian(double real, double imaginary)
    {
        return new Complex(real, imaginary);
    }

    public static Complex FromPolar(double modulus, double angle)
    {
        return new Complex(modulus * Math.Cos(angle), modulus * Math.Sin(angle));
    }

    private Complex(double real, double imaginary)
    {
        this._real = real;
        this._imaginary = imaginary;
    }
}

Complex product = Complex.FromPolar(1, Math.PI);

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

Инкапсуляция

[ редактировать ]

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

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

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

public class ImageReaderFactory {
    public static ImageReader createImageReader(ImageInputStreamProcessor iisp) {
        if (iisp.isGIF()) {
            return new GifReader(iisp.getInputStream());
        }
        else if (iisp.isJPEG()) {
            return new JpegReader(iisp.getInputStream());
        }
        else {
            throw new IllegalArgumentException("Unknown image type.");
        }
    }
}
class Factory
{
    public static function build(string $type): FormatInterface
    {
        $class = "Format" . $type;
        return new $class;
    }
}

interface FormatInterface {}

class FormatString implements FormatInterface {}
class FormatNumber implements FormatInterface {}

try {
    $string = Factory::build("String");
} catch (Error $e) {
    echo $e->getMessage();
}

try {
    $number = Factory::build("Number");
} catch (Error $e) {
    echo $e->getMessage();
}

Ограничения

[ редактировать ]

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

  • Первое ограничение заключается в том, что рефакторинг существующего класса для использования фабрик нарушает работу существующих клиентов. Например, если бы класс Complex был стандартным классом, у него могло бы быть множество клиентов с таким кодом:
    Complex c = new Complex(-1, 0);
    
Как только мы понимаем, что необходимы две разные фабрики, мы меняем класс (на код, показанный ранее ). Но поскольку конструктор теперь является частным, существующий клиентский код больше не компилируется.
  • Второе ограничение заключается в том, что, поскольку шаблон основан на использовании частного конструктора, класс не может быть расширен. Любой подкласс должен вызывать унаследованный конструктор, но этого невозможно сделать, если этот конструктор является закрытым.
  • Третье ограничение состоит в том, что если класс необходимо расширить (например, сделав конструктор защищенным — это рискованно, но осуществимо), подкласс должен предоставить собственную повторную реализацию всех фабричных методов с точно такими же сигнатурами. Например, если класс StrangeComplex простирается Complex, тогда, если StrangeComplex предоставляет свою собственную версию всех фабричных методов, вызов
    StrangeComplex.FromPolar(1, Math.Pi);
    
    даст экземпляр Complex (суперкласс), а не ожидаемый экземпляр подкласса. Функции отражения некоторых языков позволяют избежать этой проблемы.

Все три проблемы можно решить, изменив базовый язык программирования, чтобы сделать фабрики первоклассными членами класса (см. также Виртуальный класс ). [ 10 ]

Примечания

[ редактировать ]
  1. ^ С точки зрения интерфейса любой объект, возвращающий объект, может использоваться как фабрика, но семантически фабрика возвращает либо вновь созданный объект, например экземпляр класса или копию прототипа, либо объект, который выглядит новым, например повторный объект. инициализированный объект из пула объектов.
  2. ^ В языках, где конструкторы сами являются методами объекта класса ( методы класса ), существует существующий объект, а конструкторы являются особыми случаями фабричных методов, при этом полиморфное создание является особым случаем отправки полиморфного метода. В других языках существует резкое различие между конструкторами и методами.
  3. ^ Конструкторы можно использовать везде, где это возможно, на фабриках, поскольку они представляют собой особый случай.
  4. ^ Этот класс является подклассом dict, встроенная реализация сопоставлений или словарей Python.
  5. ^ Если необязательное ключевое слово new опущено.
  1. ^ Гамма, Эрих (1994). Шаблоны проектирования . Аддисон-Уэсли. стр. 18–19. ISBN  9780321700698 .
  2. ^ « Фабрика шаблонов », OODesign.com
  3. ^ Фабричный шаблон , WikiWikiWeb
  4. ^ Jump up to: а б Глава 4. Фабричный шаблон: выпечка с OO Goodness. Архивировано 11 марта 2017 г. на Wayback Machine : Определение простой фабрики. Архивировано 19 февраля 2014 г. на Wayback Machine.
  5. ^ « 30.8 Классы - это объекты: фабрики общих объектов », Изучение Python, Марк Лутц, 4-е издание, O'Reilly Media, Inc., ISBN   978-0-596-15806-4
  6. ^ Фабричный метод , WikiWikiWeb
  7. ^ объекты defaultdict
  8. ^ Перья, Майкл (октябрь 2004 г.). Эффективная работа с устаревшим кодом . Аппер-Сэддл-Ривер, Нью-Джерси: Профессиональный технический справочник Прентис-Холла. ISBN  978-0-13-117705-5 .
  9. ^ Физерс, Майкл (октябрь 2004 г.), Эффективная работа с устаревшим кодом , Аппер-Сэддл-Ривер, Нью-Джерси: Профессиональный технический справочник Прентис-Холл, ISBN  978-0-13-117705-5
  10. ^ Агербо, Эллен; Корнилс, Айно (1998). «Как сохранить преимущества шаблонов проектирования». Конференция по языкам и приложениям объектно-ориентированных систем программирования . Ванкувер, Британская Колумбия, Канада: ACM: 134–143. ISBN  1-58113-005-8 .
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 89429e1341be626244af781ba1258e0c__1719799980
URL1:https://arc.ask3.ru/arc/aa/89/0c/89429e1341be626244af781ba1258e0c.html
Заголовок, (Title) документа по адресу, URL1:
Factory (object-oriented programming) - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)