stringtranslate.com

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

Фабричный метод в LePUS3

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

Мотив

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

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

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

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

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

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

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

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

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

# collections.defaultdict([default_factory[, ...]]) d  =  defaultdict ( список )

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

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

Примеры

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

def  f ():  возврат  A ()

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

def  f ( )  : если  f.obj равен None : f.obj = A ( ) return f.obj       f . obj  =  Нет

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

Синтаксис

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

Семантика

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

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

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

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

Приложения

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

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

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

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

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

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

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

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

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

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

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

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

открытый класс Complex { открытый double _real ; открытый double _imaginary ;         public static Complex FromCartesian ( двойной действительный , двойной мнимый ) { return new Complex ( действительный , мнимый ); }             public static Complex FromPolar ( двойной модуль , двойной угол ) { return new Complex ( модуль * Math . Cos ( угол ), модуль * Math . Sin ( угол )); }                 частный комплекс ( двойной действительный , двойной мнимый ) { this._real = действительный ; this._imaginary = мнимый ; } }            Комплексное произведение = Complex.FromPolar ( 1 , Math.PI ) ;    

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

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

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

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

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

Ява

public class ImageReaderFactory { public static ImageReader createImageReader ( ImageInputStreamProcessoriisp ) { if ( iisp.isGIF ( ) ) { return new GifReader ( iisp.getInputStream ( ) ) ; } else if ( iisp.isJPEG ( ) ) { return new JpegReader ( iisp.getInputStream ( ) ); } else { throw new IllegalArgumentException ( "Неизвестный тип изображения." ); } } }                               

PHP

class  Factory {  public  static  function  build ( string  $type ) :  FormatInterface  {  $class  =  "Format"  .  $type ;  return  new  $class ;  } }интерфейс  ФорматИнтерфейс  {}класс  FormatString  реализует  FormatInterface  {} класс  FormatNumber  реализует  FormatInterface  {}попробуйте  {  $string  =  Factory :: build ( "Строка" ); }  catch  ( Ошибка  $e )  {  echo  $e -> getMessage (); }try  {  $number  =  Factory :: build ( "Number" ); }  catch  ( Ошибка  $e )  {  echo  $e -> getMessage (); }

Пределы

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

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

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

Примечания

  1. ^ С точки зрения интерфейса любой объект, возвращающий объект, может использоваться в качестве фабрики, но семантически фабрика возвращает либо вновь созданный объект, например экземпляр класса или копию прототипа, либо объект, который выглядит новым, например повторно инициализированный объект из пула объектов.
  2. ^ В языках, где конструкторы являются методами объекта класса ( методы класса ), есть существующий объект, а конструкторы являются частными случаями методов-фабрик, при этом полиморфное создание является частным случаем диспетчеризации полиморфных методов. В других языках существует четкое различие между конструкторами и методами.
  3. ^ Конструкторы можно использовать везде, где можно использовать фабрики, поскольку они представляют собой особый случай.
  4. ^ Этот класс является подклассом dict, встроенной реализации сопоставлений или словарей в Python.
  5. ^ Если необязательное ключевое слово newпропущено.

Ссылки

  1. ^ Гамма, Эрих (1994). Шаблоны проектирования . Addison-Wesley. стр. 18–19. ISBN 9780321700698.
  2. ^ Фабричный шаблон , OODesign.com
  3. ^ Фабричный образец, WikiWikiWeb
  4. ^ ab Глава 4. Модель «Фабрика»: Выпечка с использованием OO Goodness Архивировано 11.03.2017 на Wayback Machine : Определение «Простая фабрика» Архивировано 19.02.2014 на Wayback Machine
  5. ^ 30.8 Классы — это объекты: универсальные фабрики объектов , Изучаем Python, Марк Лутц, 4-е издание, O'Reilly Media, Inc., ISBN 978-0-596-15806-4 
  6. ^ Фабричный метод, WikiWikiWeb
  7. ^ объекты defaultdict
  8. ^ Feathers, Michael (октябрь 2004). Эффективная работа с устаревшим кодом . Upper Saddle River, Нью-Джерси: Prentice Hall Professional Technical Reference. ISBN 978-0-13-117705-5.
  9. ^ Feathers, Michael (октябрь 2004). Эффективная работа с устаревшим кодом . Upper Saddle River, NJ: Prentice Hall Professional Technical Reference. ISBN 978-0-13-117705-5.
  10. ^ Агербо, Эллен; Корнилс, Айно (1998). «Как сохранить преимущества шаблонов проектирования». Конференция по языкам и приложениям объектно-ориентированных систем программирования . Ванкувер, Британская Колумбия, Канада: ACM: 134–143. ISBN 1-58113-005-8.