Заменяет ли функциональное программирование шаблоны проектирования GoF?

с тех пор, как я начал изучать F# и OCaml в прошлом году, я прочитал огромное количество статей, которые настаивают на том, что шаблоны проектирования (особенно в Java) являются обходными путями для отсутствующих функций на императивных языках. Одна статья, которую я нашел делает довольно сильное заявление:

большинство людей, которых я встречал, читали Дизайн шаблоны книга банда Четыре. Любой уважающий себя программист скажу вам, что книга языка программирования и модели применить к программной инженерии в общие сведения, независимо от языка вы используете. Это благородное требование. К сожалению, это далеко от правда.

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

основные особенности функционала Программирование включает функции как первоклассные значения, currying, неизменяемые значения, etc. Мне не кажется очевидным, что шаблоны проектирования OO аппроксимируют любую из этих функций.

кроме того, в функциональных языках, поддерживающих ООП (таких как F# и OCaml), мне кажется очевидным, что программисты, использующие эти языки, будут использовать те же шаблоны проектирования, которые доступны для любого другого языка ООП. На самом деле, прямо сейчас я использую F# и OCaml каждый день, и нет никаких поразительных различия между шаблонами, которые я использую в этих языках, и шаблонами, которые я использую, когда пишу на Java.

есть ли правда в утверждении, что функциональное программирование устраняет необходимость в шаблонах проектирования ООП? Если да, можете ли вы опубликовать или связать пример типичного Шаблона дизайна ООП и его функционального эквивалента?

16 ответов


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

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

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

вот что банда четырех должна сказать об этом вопросе:

выбор языка программирования важен, потому что он влияет на точку зрения. Наши шаблоны предполагают функции языка Smalltalk / C++, и этот выбор определяет, что может и не может быть реализовано легко. Если бы мы предположили процедурные языки, мы могли бы включить шаблоны проектирования, называемые "наследование", "инкапсуляция" и "полиморфизм". Аналогично, некоторые из наших шаблоны поддерживаются непосредственно менее распространенными объектно-ориентированными языками. Например, CLOS имеет несколько методов, которые уменьшают потребность в шаблоне, таком как посетитель. На самом деле, есть достаточно различий между Smalltalk и C++, чтобы означать, что некоторые шаблоны могут быть выражены более легко на одном языке, чем на другом. (См., например, Iterator.)

(приведенная выше цитата из Введения к книге шаблонов проектирования, стр. 4, пункт 3)

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

Что такое шаблон команды, если не аппроксимация функций первого класса? :) На языке FP вы просто передадите функцию в качестве аргумента другой функции. На языке ООП вы должны обернуть функцию в класс, который вы можете создать экземпляр, а затем передать этот объект другой функции. Эффект тот же, но в ООП это называется шаблоном дизайна, и для этого требуется намного больше кода. А что такое абстрактный заводской шаблон, если не карри? Передавайте параметры функции немного за раз, чтобы настроить, какое значение она выплевывает, когда вы ее, наконец, вызываете.

Так что да, несколько шаблонов дизайна GoF становятся избыточными на языках FP, потому что более мощные и простые в использовании альтернативы существовать.

но конечно есть еще шаблоны проектирования, которые являются не решается языками FP. Что такое эквивалент FP синглтона? (Игнорируя на мгновение, что синглеты обычно являются ужасным шаблоном для использования)

и это работает в обоих направлениях. Как я уже сказал, У FP тоже есть свои шаблоны дизайна, люди просто обычно не думают о них как о таковых.

но вы, возможно, столкнулись с монадами. Каковы они, если не шаблон дизайна для " работы с глобальное государство"? Это проблема, которая настолько проста в языках ООП, что там нет эквивалентного шаблона проектирования.

нам не нужен шаблон дизайна для " увеличения статической переменной "или" чтения из этого сокета", потому что это именно то, что вы do.

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

кроме того, в функциональных языках какая поддержка ООП (например, F# и OCaml), мне кажется очевидным, что программисты, использующие эти языки будет использовать те же шаблоны проектирования найдено доступным для каждого другого ООП язык. На самом деле, прямо сейчас я использую F# и OCaml каждый день, и нет разительного отличия шаблоны, которые я использую в этих языках vs шаблоны, которые я использую, когда пишу Ява.

возможно, потому, что ты все еще думаешь императивно? Многие люди, имея дело с императивными языками всю свою жизнь, с трудом отказываются от этой привычки, когда пытаются использовать функциональный язык. (Я видел некоторые довольно забавные попытки на F#, где буквально каждый функция была просто строкой операторов "let", в основном, как если бы вы взяли программу C и заменили все точки с запятой на "let". :))

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

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

есть ли правда в утверждении, что функциональное программирование исключает нужна для моделей дизайна ООП?

да. :) Когда вы работаете на языке FP, вам больше не нужны шаблоны проектирования, специфичные для ООП. Но вы все еще нужны некоторые общие шаблоны дизайна, такие как MVC или другие не-ООП-специфические вещи, и вам нужна пара новых FP-специфичных "шаблонов дизайна". Все языки имеют свои недостатки, и шаблоны проектирования, как правило, как мы работаем вокруг них.

в любом случае, вам может быть интересно попробовать свои силы в" чистых " языках FP, таких как ML (мой личный фаворит, по крайней мере, для учебных целей) или Haskell, где у вас нет костыля ООП, чтобы вернуться, когда вы столкнулись с нечто новое.


как и ожидалось, несколько человек возражали против моего определения шаблонов дизайна как "исправления недостатков в языке", поэтому вот мое оправдание: Как уже было сказано, большинство шаблонов проектирования специфичны для одной парадигмы программирования, а иногда даже для одного конкретного языка. Часто они решают задачи, которые только exist в этой парадигме (см. монады для FP или абстрактные фабрики для OOP). Почему абстрактный фабричный шаблон не существует в FP? Потому что проблему он пытается решить не существует. Таким образом, если проблема существует в языках ООП, которая не существует в языках FP, то ясно, что это недостаток языков ООП. Проблема может быть решена, но ваш язык этого не делает, но требует от вас кучу шаблонного кода, чтобы обойти его. В идеале, мы хотели бы, чтобы наш язык программирования волшебным образом сделал все проблемы уходят. Любая проблема, которая все еще существует, в принципе является недостатком языка. ;)


есть ли правда в утверждении, что функциональное программирование устраняет необходимость в шаблонах проектирования ООП?

функциональное программирование-это не то же самое, что объектно-ориентированное программирование. Объектно-ориентированные шаблоны проектирования не применяются к функциональному программированию. Вместо этого у вас есть функциональные шаблоны программирования.

для функционального программирования вы не будете читать книги шаблонов дизайна OO, вы будете читать другие книги по дизайну FP узоры.

язык агностик

Не совсем. Только язык-агностик по отношению к языкам ОО. Шаблоны проектирования вообще не применяются к процедурным языкам. Они едва ли имеют смысл в контексте проектирования реляционной базы данных. Они не применяются при разработке электронных таблиц.

типичный шаблон проектирования ООП и его функциональный эквивалент?

вышеизложенное не должно существовать. Вот как просят часть процессуального кодекса переписана как код ОО. МММ... Если я переведу оригинальный Fortran (или C) на Java, я ничего не сделал, кроме как перевести его. Если я полностью перепишу его в парадигму ОО, он больше не будет выглядеть как оригинальный Фортран или С-он будет неузнаваем.

нет простого сопоставления от дизайна OO до функционального дизайна. Они по-разному смотрят на проблему.

функциональное программирование (как все стили программирования) имеет шаблоны проектирования. Реляционные базы данных имеют шаблоны проектирования, OO имеет шаблоны проектирования, процедурное программирование имеет шаблоны проектирования. Все имеет узоры дизайна, даже архитектура зданий.

шаблоны проектирования - как концепция-это вневременной Способ построения, независимо от технологии или проблемной области. Однако конкретные шаблоны проектирования применяются к конкретным проблемным областям и технологиям.

каждый, кто мысли о том, что они делают, раскроют шаблоны дизайна.


комментарии Брайана о тесной связи между языком и шаблоном в точку,

недостающей частью этого обсуждения является концепция идиомы. Книга коплиена "Advanced C++" оказала здесь огромное влияние. Задолго до того, как он обнаружил Кристофера Александра и ... --3-->столбец без имени (и вы не можете разумно говорить о шаблонах, не читая Александра), он говорил о важности овладения идиомой в истинном изучении языка. Он использовал строку скопируйте в C в качестве примера, while (*from++ = * to++); вы можете видеть это как полосу для отсутствующей языковой функции (или библиотечной функции), но что действительно имеет значение, так это то, что это большая единица мысли или выражения, чем любая из ее частей.

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

мы также можем, как люди, учиться. В этом весь смысл упражнения. Каждый из нас может понять и использовать то, о чем никогда не сможет думать сам. Языки, фреймворки, библиотеки, шаблоны, идиомы и так далее-все это имеет свое место в разделении интеллектуального богатства.


книга GOF явно связывает себя с ООП-название-шаблоны дизайна-элементы многоразового использования Объектно-Ориентированное программное обеспечение (выделено мной.)


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


вот еще одна ссылка, обсуждающая эту тему:http://blog.ezyang.com/2010/05/design-patterns-in-haskel/

в своем блоге Эдвард описывает все 23 оригинальных шаблона GoF с точки зрения Haskell.


когда вы попытаетесь взглянуть на это на уровне "шаблонов дизайна" (в целом) и "FP против ООП", ответы, которые вы найдете, будут в лучшем случае мутными.

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

Итак, например, некоторые конкретные шаблоны, такие как гость, стратегия, команда, и Обозреватель определенно изменить или исчезнуть при использовании языка с алгебраические типы данных и сопоставление с образцом, закрытие, функции, etc. Некоторые другие шаблоны из книги GoF все еще "держатся".

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

(в сторону: вот последние блог я написал, что имеет другие ссылки на более подробное обсуждение шаблонов FP и дизайна.)


презентация Norvig ссылается на анализ, который они сделали из всех шаблонов GoF, и они говорят, что 16 из 23 шаблонов имели более простые реализации на функциональных языках или были просто частью языка. Таким образом, по-видимому, по крайней мере семь из них были либо а) одинаково сложными, либо б) отсутствовали в языке. К сожалению для нас, они не перечислены!

Я думаю, ясно, что большинство "творческих" или "структурных" моделей в GoF-это просто трюки, чтобы получить примитивные системы типов в Java или C++, чтобы делать то, что вы хотите. Но остальные заслуживают внимания независимо от того, на каком языке вы программируете.

один может быть прототипом; хотя это фундаментальное понятие JavaScript, оно должно быть реализовано с нуля на других языках.

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


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


и даже решения шаблона проектирования OO специфичны для языка. Шаблоны проектирования-это решения общих проблем, которые ваш язык программирования не решает для вас. В Java одноэлементный шаблон решает единственную (упрощенную) проблему. В Scala у вас есть конструкция верхнего уровня, называемая Object в дополнение к Class. Он лениво создан, и есть только один. Вам не нужно использовать шаблон Singleton, чтобы получить Синглтон. Это часть языка.


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

посмотрите, как Scala устраняет "одноэлементный шаблон": вы просто объявляете объект вместо класса. Другая особенность, соответствие рисунка, помогает избежать неуклюжести шаблона посетителя. См. Сравнение здесь: http://andymaleh.blogspot.com/2008/04/scalas-pattern-matching-visitor-pattern.html

и Scala, как и F#, является слиянием OO-функционала. Я не знаю о F#, но у него, вероятно, есть такие функции.

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

еще одно наблюдение. Этот фрагмент кода реализует шаблон: это такая классика, и это так элементарно что мы обычно не думаем об этом как о "шаблоне", но это точно:

for(int i = 0; i < myList.size(); i++) { doWhatever(myList.get(i)); }

императивные языки, такие как Java и C#, приняли то, что по существу является функциональной конструкцией для решения этого: "foreach".


Шаблоны-это способы решения подобных проблем, которые видны снова и снова, а затем описываются и документируются. Так что нет, FP не собирается заменять шаблоны; однако FP может создавать новые шаблоны и делать некоторые текущие шаблоны "лучших практик" "устаревшими".


шаблоны проектирования GoF кодируют обходные рецепты для языков OO, которые являются потомками Simula 67, таких как Java и c++.

большинство "недугов", обработанных шаблонами дизайна, вызваны:

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

нет ни одного из этих шаблонов дизайна, который не исчезает в общем Объектная система Lisp, хотя решение структурировано по существу так же, как и в соответствующем шаблоне проектирования. (Более того, эта объектная система предшествует книге GoF более чем на десятилетие. Common Lisp стал стандартом ANSI в том же году, когда эта книга была впервые опубликована.)

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

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

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


Я хотел бы подключить пару отличных, но несколько плотных документов Джереми Гиббонса: "шаблоны проектирования как тип данных более высокого порядка-общие программы" и " сущность шаблона итератора "(оба доступны здесь:http://www.comlab.ox.ac.uk/jeremy.gibbons/publications/).

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


вы не можете обсуждать это, не поднимая системы типов.

основные характеристики функционального программирования включают функции как первоклассные значения, currying, неизменяемые значения, etc. Мне не кажется очевидным, что шаблоны проектирования OO аппроксимируют любую из этих функций.

Это потому, что эти функции не решают те же проблемы, что и ООП... они являются альтернативами императивному программированию. Ответ FP на ООП лежит в тип систем ML и Haskell... в частности, типы суммирования, абстрактные типы данных, модули ML, Haskell typeclasses.

но, конечно, есть еще шаблоны проектирования, которые не решаются языками FP. Что такое эквивалент FP синглтона? (Игнорируя на мгновение, что синглеты обычно являются ужасным шаблоном для использования)

первое, что делают typeclasses, это устранить необходимость в синглетах.

вы можете просмотреть список 23 и устранить больше, но у меня нет времени прямо сейчас.


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