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


1047

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

Большинство людей, которых я встречал, читали книгу «Банды четырех» (GoF). Любой уважающий себя программист скажет вам, что книга не зависит от языка, и шаблоны применимы к разработке программного обеспечения в целом, независимо от того, какой язык вы используете. Это благородное требование. К сожалению, это далеко от истины.

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

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

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

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


18
Вы можете взглянуть на статью Стива Йегге ( steve-yegge.blogspot.com/2006/03/… )
Ральф,

27
«Книга не зависит от языка, и шаблоны применимы к разработке программного обеспечения в целом». Следует отметить, что книга не согласна с этим утверждением в том смысле, что некоторым языкам не нужно выражать определенные вещи, например шаблоны проектирования: «Наши шаблоны предположить возможности языка уровня Smalltalk / C ++, и этот выбор определяет, что может и не может быть легко реализовано [...] CLOS имеет, например, несколько методов, которые уменьшают потребность в шаблоне, таком как Visitor (стр. 331). " (страница 4)
Гильденстерн

6
Также имейте в виду, что многие шаблоны проектирования даже не нужны в императивных языках достаточно высокого уровня.
Р. Барзелл

3
@ R.Barzell Что это за «достаточно высокий уровень императивных языков»? Спасибо.
cibercitizen1

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

Ответы:


1077

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

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

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

Вот что говорит Банда Четырех по этому вопросу:

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

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

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

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

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

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

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

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

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

Сказать, что монада - это шаблон проектирования, так же абсурдно, как сказать, что целые числа с их обычными операциями, а нулевой элемент - это шаблон проектирования. Нет, монада - это математическая модель , а не модель дизайна.

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

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

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

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

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

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

Ага. :) Когда вы работаете на языке FP, вам больше не нужны специфичные для ООП шаблоны проектирования. Но вам все еще нужны некоторые общие шаблоны проектирования, такие как MVC или другие, не относящиеся к ООП, вещи, и вместо этого вам понадобится пара новых специфических для FP «шаблонов проектирования». У всех языков есть свои недостатки, и шаблоны проектирования обычно таковы, как мы их обходим.

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


Как и ожидалось, несколько человек возразили против моего определения шаблонов проектирования как «исправление недостатков в языке», поэтому вот мое оправдание:

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

Почему абстрактный шаблон фабрики не существует в FP? Потому что проблемы, которую он пытается решить, там не существует.

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


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

135
С.Лотт: Да, они описывают решения проблем, существующих на данном языке. В языках FP отсутствует шаблон проектирования Command, поскольку проблемы, которую он пытается решить, не существует. Это означает, что они решают проблемы, которые сам язык не может решить. То есть недостатки в языке
jalf 30.11.08

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

41
Конечно, монады - это математическое понятие, но они также и шаблон. «Образец FP» монад несколько отличается от математического понятия монад. Первый - это шаблон, используемый для обхода определенных «ограничений» в чистых языках FP. Последнее является универсальным математическим понятием.
Джалф

69
Обратите внимание, что монады в Haskell используются не для изменяемого состояния, а для других целей, например, для исключений, продолжений, составления списков, анализа, асинхронного программирования и так далее. Но все эти применения монад можно было бы назвать шаблонами.
JacquesB

152

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

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

Для функционального программирования вы не будете читать книги шаблонов проектирования ОО; Вы будете читать другие книги по шаблонам проектирования FP.

языковая независимость

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

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

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

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

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

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

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


12
MVC это не ОО дизайн. Это архитектурный дизайн - этот шаблон применяется довольно широко.
S.Lott

1
@Princess: функциональное программирование не обязательно проще. В вашем примере да. Что касается других вещей, жюри все еще нет. Но вы отказались от шаблона проектирования Java OO и приняли шаблон проектирования FP.
S.Lott

1
+1: я предпочитаю этот ответ ответу Джальфа выше. Хотя некоторые шаблоны проектирования устраняют недостатки языка, не все это делают. Например, я бы вряд ли сказал, что шаблон проектирования «развязывание рекурсивного узла» устраняет недостаток в языке, это просто полезная идиома для ослабления зависимостей.
Джон Харроп

9
Java 8 будет включать замыкания, известные как анонимные функции или лямбда-выражения. Это сделает шаблон проектирования команд устаревшим для Java. Это пример языкового недостатка, нет? Они добавили отсутствующую функцию, и теперь вам не нужен шаблон дизайна.
Тодд Чаффи

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

46

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

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

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

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


8
Спасибо! вот что такое паттерны - «концептуальное чанкинг» для снижения когнитивного бремени.
Рэндалл Шульц

И Функциональные Монады определенно принадлежат этой дискуссии.
Грег

@RandallSchulz: языковые функции (и их идиоматическое использование, конечно) также хорошо вписываются в категорию «концептуальное разделение на части для снижения когнитивной нагрузки».
Рой Тинкер

39

Книга GoF явно связана с ООП - название «Шаблоны проектирования» - элементы многоразового объектно-ориентированного программного обеспечения (выделено мной).



26

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

В своем блоге Эдвард описывает все 23 оригинальных паттерна GoF в терминах Haskell.


4
Кажется, что статья не показывает шаблоны проектирования в Haskell, но показывает, как Haskell удовлетворяет эти потребности без использования указанных шаблонов.
Fresheyeball

3
@Fresheyball: зависит от вашего определения шаблонов. Является ли отображение функции по списку вариантом шаблона посетителя? Я вообще думал, что ответ был "да". Предполагается, что шаблоны выходят за рамки определенного синтаксиса. Применяемая функция может быть обернута как объект или передана как указатель на функцию, но концепция для меня та же. Вы не согласны?
SRM

20

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

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

Так, например, некоторые конкретные шаблоны, такие как Visitor , Strategy , Command и Observer, определенно изменяются или исчезают при использовании языка с алгебраическими типами данных и сопоставлением с образцом образцами , замыканий , функций первого класса и т. Д. Некоторые другие шаблоны из книги GoF по-прежнему «держись», хотя.

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

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


Как вы можете сказать, что шаблон посетителя «исчезает»? Разве он не превращается из «сделать интерфейс посетителя с помощью множества методов посещения» в «использовать типы объединения и сопоставление с образцом»?
Гейб

22
Да, но это изменилось от паттерна, который является идеей дизайна, о которой вы читаете в книге и применяете к своему коду, к «просто коду». То есть «использовать типы объединения и сопоставление с образцом» - это то, как вы обычно кодируете вещи на таком языке. (Аналогия: если ни в одном из языков не было forциклов и все они имели whileциклы, тогда «For» мог бы быть шаблоном итерации. Но когда forэто просто конструкция, поддерживаемая языком, и то, как люди обычно кодируют, тогда это не шаблон - вы не не нужен шаблон, это просто код, чувак.)
Брайан,

4
Другими словами, возможно, неплохой лакмусовый тест для «это шаблон» таков: представьте код, написанный таким образом, для студентов второго курса, изучающих CS, с годичным опытом программирования на вашем языке. Если вы покажете им код, и они скажут: «Это умный дизайн», то это шаблон. Если вы покажете им код, и они скажут: «Ну, да!», То это не шаблон. (И если вы покажете этого «Посетителя» любому, кто занимался ML / F # / Haskell в течение года, они пойдут «хорошо, да!»)
Брайан,

1
Брайан: Я думаю, что у нас просто разные определения «шаблона». Я считаю любую идентифицируемую абстракцию дизайна шаблоном , в то время как вы рассматриваете только неочевидные абстракции как шаблон . То, что в C # есть, foreachа в Haskell mapM, не означает, что у них нет шаблона Iterator. Я не вижу проблем в том, что шаблон Iterator реализован как универсальный интерфейс IEnumerable<T>в C # и класс типов Traversableв Haskell.
Гейб

Возможно, что неочевидные шаблоны полезны для разработчиков программного обеспечения, но все шаблоны полезны для разработчиков языков. Т.е. «Если вы создаете новый язык, обязательно включите чистый способ выражения шаблона итератора». Даже очевидные закономерности представляют интерес, когда мы начинаем задавать вопрос: «Есть ли лучший синтаксис для выражения этой идеи?» В конце концов, это то, что заставляет кого-то создавать foreach.
SRM

16

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

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

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

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


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

@munulous: Не совсем. Объектная ориентация обеспечивает полиморфизм; Функциональное программирование обычно обеспечивает полиморфизм.
Марцин

@ Марчин, специалист по ОО, по полиморфизму означает нечто совершенно иное, чем функциональный программист.
AndrewC

@AndrewC Я не согласен. Программист OO может думать, что они имеют в виду что-то другое, но это не так.
Marcin

3
@Marcin По моему опыту, программист OO обычно ссылается на полиморфизм подтипа (часто просто используя Object), использует приведения для его достижения или специальный полиморфизм (перегрузка и т. Д.). Когда функциональный программист говорит полиморфизм, он подразумевает параметрический полиморфизм (т.е. работает для любого типа данных - Int, function, list), который, возможно, больше похож на универсальное программирование ОО, чем на что-либо, что программисты ОО обычно называют полиморфизмом.
AndrewC

15

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


Я полностью потерян. Чтобы создать что-то с помощью абстракций ... Что это значит?
Tuinstoel

2
Вы можете создавать предметные абстракции (даже встроенные) без макросов. Макросы просто позволяют вам создавать их, добавляя собственный синтаксис.
Джон Харроп

2
Вы можете думать о Лиспе как о наборе Legos для построения языков программирования - это язык, но это также метаязык. Это означает, что для любой проблемной области вы можете разработать язык, не имеющий явных недостатков. Это потребует некоторой практики, и Курт Гёдель может не согласиться, но стоит потратить некоторое время с Лиспом, чтобы посмотреть, что он принесет на стол (подсказка, макросы).
Грег

9

И даже решения шаблонов проектирования ОО зависят от языка.

Шаблоны проектирования - это решение общих проблем, которые ваш язык программирования не решает за вас. В Java шаблон Singleton решает проблему «что-то одно» (упрощенное).

В Scala у вас есть конструкция верхнего уровня под названием Object в дополнение к Class. Это ленивый экземпляр и есть только один. Вам не нужно использовать шаблон Singleton, чтобы получить Singleton. Это часть языка.


8

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


4
Шаблоны GoP - это способы решения проблемы ограничений конкретного типа языка программирования. Например, «Я хочу косвенно обращаться к классам и сказать им, чтобы они создавали объекты» -> «Вы не можете, но вы можете создавать объекты, подобные метаклассам, называемые Фабрикой». «Я хочу многократную отправку» -> «Вы не можете, но есть лабиринт, который вы можете реализовать, называемый Шаблон посетителя». И т.д. Ни один из шаблонов не имеет смысла, если вы не используете язык ООП с конкретными ограничениями.
Каз

1
Я не знаю, что «ни один» не имеет смысла на других языках, но я согласен, что многие из них не имеют смысла на других языках. Адаптер и Bridge, кажется, имеют больше многоязычных возможностей, немного уменьшая для посетителя и, возможно, немного меньше для слушателя. Тем не менее, шаблоны разных языков всегда будут страдать от типа «как выполнять операции языка X на языке Y», ограничивающего естественные границы языка. Прекрасным примером был паттерн Синглтона, который, в основном, как мне получить C глобалы в ООП? (что я отвечу, вы не должны).
Эдвин Бак

1
Второй вариант Kaz: Pattern - это не «способ решения похожих проблем, которые видны снова и снова», а «способ решения похожих проблем, которые видны снова и снова» И их нужно переписывать снова и снова, потому что язык не позволяет напиши это только один раз ". Другими словами, если язык допускает извлечение / абстрагирование шаблона в библиотеке / классе / модуле и т. Д., Он перестает быть шаблоном, но становится библиотекой / классом / модулем. В FP намного проще извлекать / абстрагировать бит кодов в функцию, поэтому «шаблоны» легче конвертировать в повторно используемый код, делая их не шаблонами.
mb14

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

1
Возвращаясь к этому разговору спустя годы, я думаю, что многие люди связывают паттерны с определенным языком программирования или конкретной парадигмой программирования. Их можно использовать в таком контексте, но они существовали до программирования. «Вневременный способ строительства» обсуждает принципы построения архитектуры и планирования сообщества. Это подразумевает, что шаблонно-ориентированные методы могут использоваться вне «ограничений языка», если только вы не хотите называть конструкцию здания языком программирования :)
Edwin Buck

8

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

Посмотрите, как Scala избавляется от «шаблона синглтона»: вы просто объявляете объект вместо класса. Другая особенность, сопоставление с образцом, помогает избежать грубости шаблона посетителя. Смотрите сравнение здесь: Scala's Pattern Matching = Шаблон посетителя на стероидах

А Scala, как и F #, представляет собой слияние ОО-функционала. Я не знаю о F #, но он, вероятно, имеет такие особенности.

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

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

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

В императивных языках, таких как Java и C #, принята функциональная конструкция для решения этой проблемы: «foreach».


Я бы сказал, что Scala включает первоклассную поддержку одноэлементного шаблона. Шаблон все еще существует, но стандартный код, необходимый для его применения, значительно сокращен по сравнению с Java.
JacquesB

Если бы мнения были похожи на *******, хорошо ... Посмотрите на остальные ответы. «Вы просто объявляете объект вместо класса», это правда, я бы явно назвал его литералом объекта (то есть, var singleton = {};). Мне также нравится упоминание о шаблоне foreach. К сожалению, похоже, что большинство людей, которые ответили / прокомментировали этот вопрос, не понимают функциональное программирование и скорее оправдывают использование шаблонов проектирования ООП. +1 за конкретные примеры, я бы дал больше, если бы мог.
Эван Плейс

@JacquesB Я не могу комментировать Scala / Haskell, но в JavaScript (т. Е. Гибридный функционал / императив) нет абсолютно никакого шаблона, вы просто настраиваете способ объявления объектов, используя комбинации синтаксиса литералов объектов, анонимных функций, передавая функции в первую очередь члены класса и разрешают множественное наследование (устраняя необходимость в интерфейсных контрактах).
Эван Плейс

8

GoF Design Patterns кодирует обходные рецепты для ОО-языков, которые являются потомками Simula 67 , таких как Java и C ++.

Большинство "недугов", с которыми сталкиваются шаблоны проектирования, вызваны:

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

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

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

Конструкция и доступ без мутаций совместимы с функциональным программированием, поэтому могут применяться шаблоны, связанные с абстрагированием доступа или конструированием: шаблоны, такие как Factory, Facade, Proxy, Decorator и Visitor.

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


2
«Шаблоны дизайна GoF - это рецепты обходного пути» - это просто ложное утверждение.
Джон Питерс

7

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

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


6

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

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

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

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

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

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


6
Как классы типов (эквивалент FP интерфейсов ООП) устраняют необходимость в синглетонах (эквивалент FP глобального состояния)?
Гейб

4

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


4
Дело в том, что главное в многих шаблонах - использовать полиморфизм для того, чтобы автоматически делать приличную поддержку концепций FP. (Например, большинство воплощений, которые я видел в Builder, - это всего лишь наполовину карри.) Как только вы можете легко рассматривать функции как значения, шаблоны часто упрощаются до степени тривиальности. Они становятся «передать обратный вызов» или «иметь словарь обратных вызовов» - и, например, различные классы компоновщиков могут почти исчезнуть. IMO шаблон перестает быть шаблоном, если он достаточно тривиален, чтобы понять, как все работает , а не то, что вам нужно реализовать.
Чао

4

По сути, да !

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

Кроме того, эта страница (AreDesignPatternsMissingLanguageFeatures) содержит таблицу перевода «шаблон / функция» и некоторые приятные обсуждения, если вы хотите копать.


3

Функциональное программирование не заменяет шаблоны проектирования. Дизайн моделей не подлежит замене.

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


1
Дизайн моделей не может быть заменен? Это немного закрыто, я думаю. Вероятно, все мы можем согласиться с тем, что шаблоны проектирования предназначены для решения задач программирования, и я, по крайней мере, хотел бы надеяться, что когда-нибудь мы сможем решить эти проблемы без шаблонов проектирования.
Метрополис

3
Любой конкретный шаблон может быть заменяемым, но концепция шаблонов не может. Помните, что термин «шаблон» возник в области архитектуры .
Фрэнк Шиарар

1
Шаблоны не предназначены для решения задач программирования. Шаблоны - это способы, которыми мы программируем. Документация шаблонов предназначена для решения проблем программирования.
Torbjørn

3
@ Torbjørn: Шаблоны - это способы, которыми мы программируем, когда язык мешает . Они существуют из-за некоторого несоответствия между желаемым поведением программы и встроенными способностями языка, где требования и способности плохо отображаются или отображаются неоднозначно. Если бы не это, не было бы образца; у вас была бы одна реализация, которая бы просто делала , а другие реализации не стоило бы рассматривать.
Чао

1
За исключением того, что шаблоны действительно существуют только для облегчения общения. Нет другой цели. И на всех встречах по дизайну, которые я посещал на протяжении многих лет, важно было обсудить алгоритм , а не шаблон. Шаблон редко объяснял то, что действительно происходило в каком-либо значимом смысле. Объясняет ли это точно влияние O (n) против O (n Log (n))? Нет. Объясняет ли это, насколько легко он будет соответствовать существующей архитектуре? Нет. Полномасштабные обсуждения алгоритма делают. Я не спорю, что шаблоны должны быть удалены как таковые, но если бы они были, почти ничего не пострадало бы в результате.

3

В новой книге 2013 года под названием «Шаблоны функционального программирования - в Scala и Clojure» автор Michael.B. Линн прилично работает, сравнивая и предоставляя замены во многих случаях для шаблонов GoF, а также обсуждает более новые функциональные шаблоны, такие как «хвостовая рекурсия», «запоминание», «ленивая последовательность» и т. Д.

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


3

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

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

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

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

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

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


2
У FP может быть состояние - просто нет глобального, общего или изменяемого состояния.
vt5491

2

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

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


1

Как говорится в принятом ответе, у ООП и ФП есть свои специфические закономерности.

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

  • Адаптер. Я с трудом могу придумать полезную платформу программирования, настолько всеобъемлющую (и самореализованную), что ей не нужно общаться с миром. Если он собирается это сделать, адаптер определенно необходим.

  • Фасад. Любые программные платформы, которые могут обрабатывать большой исходный код, должны иметь возможность модульности. Если вам нужно было создать модуль для других частей программы, вы захотите скрыть «грязные» части кода и придать ему приятный интерфейс.

  • Переводчик. В общем, любая программа просто делает две вещи: анализ ввода и вывод на печать. Входы мыши должны быть проанализированы, и виджеты окна должны быть распечатаны. Следовательно, наличие встроенного интерпретатора дает программе дополнительные возможности для настройки вещей.

Кроме того, я заметил, что в типичном языке FP, Haskell, есть нечто похожее на шаблоны GoF, но с другими именами. На мой взгляд, это говорит о том, что они были там, потому что есть некоторые общие проблемы, которые нужно решить на языках FP и OOP.

  • Монада трансформер и декоратор. Первый используется для добавления дополнительных способностей в существующую монаду, второй - для добавления дополнительных способностей к существующему объекту.

1

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

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

Я бы не использовал функциональный язык для написания пользовательского интерфейса, но один из ОО-языков, таких как C # или Java, облегчит эту работу. Если бы я писал функциональный язык, я бы не стал использовать шаблоны проектирования ОО.


1

ООП и ФП имеют разные цели. ООП стремится инкапсулировать сложности / движущиеся части программных компонентов, а FP стремится минимизировать сложность и зависимости программных компонентов.

Однако эти две парадигмы не обязательно противоречат на 100% и могут быть применены вместе, чтобы получить пользу от обоих миров.

Даже с языком, который изначально не поддерживает функциональное программирование, таким как C #, вы могли бы написать функциональный код, если вы понимаете принципы FP. Точно так же вы можете применять принципы ООП, используя F #, если вы понимаете принципы ООП, шаблоны и лучшие практики. Вы сделаете правильный выбор в зависимости от ситуации и проблемы, которую вы пытаетесь решить, независимо от используемого вами языка программирования.


1

Некоторые шаблоны легче реализовать на языке, поддерживающем FP. Например, Стратегия может быть реализована с использованием замыканий. Однако, в зависимости от контекста, вы можете предпочесть реализовать Стратегию, используя подход, основанный на классе, например, когда сами стратегии довольно сложны и / или имеют общую структуру, которую вы хотите смоделировать с помощью Template Template.

По моему опыту разработки на многопарадигмальном языке (Ruby) реализация FP хорошо работает в простых случаях, но там, где более сложный контекст, лучше подходит подход, основанный на GoF OOP.

Подход FP не заменяет подход ООП, он дополняет его.


0

Главной характеристикой функционального программирования, IMHO, является то, что вы программируете только с помощью выражений - выражений внутри выражений внутри выражений, которые все оценивают до последнего, окончательного выражения, которое «нагревает машину при оценке».

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

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


Хм, я должен был заметить, что на вопрос было 11 лет, прежде чем ответить. :-)
Джим Флуд

0

Готовьтесь.

Многим будет неприятно слышать, как я утверждаю, что заменил шаблоны проектирования и развенчал SOLID и DRY. Я - никто. Тем не менее я правильно смоделировал совместную (производственную) архитектуру и опубликовал правила построения процессов в Интернете, а также код и научные разработки, лежащие в его основе, на своем веб-сайте http://www.powersemantics.com/ .

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

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

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

Можно сказать, что ООП - это парадигма «жестко запрограммированного процесса», а шаблоны проектирования - это способы избежать этой парадигмы. Но вот что такое массовая настройка. Шаблоны проектирования воплощают динамические процессы в виде грязного жесткого кода. Там просто нет смысла. Тот факт, что F # позволяет передавать функции в качестве параметра, означает, что функциональные языки и языки ООП одинаково пытаются выполнить массовую настройку самостоятельно.

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


0

Это связано с тем, что функциональный PL высокого уровня (такой как OCaml, с классами, модулями и т. Д.), Безусловно, заменяет императивные языки ООП в универсальности типов и силе выражения. Абстракции не протекают, вы можете выразить большинство ваших идей прямо в программе. Следовательно, да, он заменяет шаблоны проектирования, большинство из которых, по крайней мере, смехотворно упрощены по сравнению с функциональными шаблонами.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.