design-patterns - quoi - product factory design pattern




La programmation fonctionnelle remplace-t-elle les modèles de conception du GoF? (16)

Existe-t-il une vérité à l'affirmation selon laquelle la programmation fonctionnelle élimine le besoin de modèles de conception OOP?

La programmation fonctionnelle n'est pas la même que la programmation orientée objet. Les modèles de conception orientés objet ne s'appliquent pas à la programmation fonctionnelle. Au lieu de cela, vous avez des modèles de conception de programmation fonctionnelle.

Pour la programmation fonctionnelle, vous ne lirez pas les livres de modèles de conception OO, vous lirez d'autres livres sur les modèles de conception de FP.

langage agnostique

Pas totalement. Seul langage-agnostique par rapport aux langues OO. Les modèles de conception ne s'appliquent pas du tout aux langages procéduraux. Ils ont à peine du sens dans un contexte de conception de base de données relationnelle. Ils ne s'appliquent pas lors de la conception d'une feuille de calcul.

un modèle de conception OOP typique et son équivalent fonctionnel?

Ce qui précède ne devrait pas exister. C'est comme demander un code de procédure réécrit comme code OO. Ummm ... Si je traduis l'original Fortran (ou C) en Java, je n'ai rien fait de plus que de le traduire. Si je le réécris totalement dans un paradigme OO, il ne ressemblera plus à l'original Fortran ou C - il sera méconnaissable.

Il n'y a pas de correspondance simple entre OO Design et Functional Design. Ce sont des façons très différentes de regarder le problème.

La programmation fonctionnelle (comme tous les styles de programmation) a des motifs de conception. Les bases de données relationnelles ont des modèles de conception, OO a des modèles de conception, la programmation procédurale a des modèles de conception. Tout a des motifs de design, même l'architecture des bâtiments.

Les modèles de conception - en tant que concept - sont un moyen de construction intemporel, indépendamment de la technologie ou du domaine du problème. Cependant, des modèles de conception spécifiques s'appliquent à des domaines et à des technologies spécifiques.

Tous ceux qui pensent à ce qu'ils font découvriront des modèles de design.

Depuis que j'ai commencé à apprendre F # et OCaml l'année dernière, j'ai lu un grand nombre d'articles qui insistent sur le fait que les modèles de design (spécialement en Java) sont des solutions de contournement pour les fonctionnalités manquantes dans les langages impératifs. Un article que j'ai trouvé fait une affirmation assez forte :

La plupart des gens que j'ai rencontrés ont lu le livre Design Patterns du Gang of Four. Tout programmeur respectueux de soi vous dira que le livre est agnostique et que les schémas s'appliquent au génie logiciel en général, quelle que soit la langue que vous utilisez. C'est une revendication noble. Malheureusement, c'est loin de la vérité.

Les langages fonctionnels sont extrêmement expressifs. Dans un langage fonctionnel, on n'a pas besoin de modèles de design parce que la langue est probablement de si haut niveau, on finit par programmer dans des concepts qui éliminent tous les modèles de design.

Les principales caractéristiques de la programmation fonctionnelle comprennent des fonctions telles que des valeurs de première classe, des valeurs immuables, des valeurs immuables, etc. Il ne me semble pas évident que les modèles de conception OO se rapprochent de ces caractéristiques.

De plus, dans les langages fonctionnels qui prennent en charge la POO (comme F # et OCaml), il me semble évident que les programmeurs utilisant ces langages utiliseraient les mêmes modèles de conception que ceux disponibles pour tous les autres langages POO. En fait, maintenant j'utilise F # et OCaml tous les jours, et il n'y a pas de différences frappantes entre les modèles que j'utilise dans ces langages et ceux que j'utilise quand j'écris en Java.

Existe-t-il une vérité à l'affirmation selon laquelle la programmation fonctionnelle élimine le besoin de modèles de conception OOP? Si oui, pourriez-vous poster ou lier un exemple de modèle de conception OOP typique et son équivalent fonctionnel?


Comme d'autres l'ont dit, il existe des modèles spécifiques de programmation fonctionnelle. Je pense que la question de se débarrasser des modèles de conception n'est pas tellement de passer à fonctionnel, mais une question de fonctionnalités linguistiques .

Jetez un oeil à la façon dont Scala supprime le "modèle singleton": vous déclarez simplement un objet au lieu d'une classe. Une autre caractéristique, l'appariement de modèles, permet d'éviter le clunkiness du modèle de visiteur. Voir la comparaison ici: http://andymaleh.blogspot.com/2008/04/scalas-pattern-matching-visitor-pattern.html

Et Scala, comme F #, est une fusion de OO-fonctionnelle. Je ne sais pas sur F # mais il a probablement ce genre de fonctionnalités.

Les fermetures sont présentes dans un langage fonctionnel, mais ne doivent pas nécessairement leur être limitées. Ils aident avec le modèle de délégant.

Une observation de plus. Ce morceau de code implémente un motif: c'est un classique et c'est tellement élémentaire qu'on ne le considère généralement pas comme un "pattern", mais c'est sûr:

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

Les langages impératifs comme Java et C # ont adopté ce qui est essentiellement une construction fonctionnelle pour faire face à cela: "foreach".


Dans le nouveau livre de 2013 intitulé "Functional Programming Patterns - in Scala and Clojure", l'auteur Michael.B. Linn fait un travail décent en comparant et fournissant des remplacements dans de nombreux cas pour les modèles du GoF et discute aussi des modèles fonctionnels plus récents comme «récursivité de la queue», «mémoisation», «séquence paresseuse», etc.

Ce livre est disponible sur Amazon. Je l'ai trouvé très instructif et encourageant quand je viens d'un arrière-plan OO de quelques décennies.


Essentiellement, oui !

  • Lorsqu'un pattern contourne les fonctionnalités manquantes (fonctions d'ordre supérieur, gestion de flux ...), ultimalty facilite la composition .
  • La nécessité de réécrire encore et encore la mise en œuvre des modèles peut elle-même être perçue comme une odeur de langage .

En outre, cette page (AreDesignPatternsMissingLanguageFeatures) fournit une table de traduction "pattern / feature" et de belles discussions, si vous êtes prêt à creuser.


Je dirais que lorsque vous avez un langage comme Lisp avec son support pour les macros, alors vous pouvez construire vos propres abstractions spécifiques au domaine, des abstractions qui sont souvent bien meilleures que les solutions idiom générales.


Je pense que chaque paradigme sert un but différent et en tant que tel ne peut être comparé de cette manière.

Je n'ai pas entendu dire que les modèles de conception du GoF sont applicables à toutes les langues. J'ai entendu dire qu'ils sont applicables à toutes les langues OOP . Si vous utilisez la programmation fonctionnelle, le domaine des problèmes que vous résolvez est différent des langages OO.

Je n'utiliserais pas de langage fonctionnel pour écrire une interface utilisateur, mais l'un des langages OO comme C # ou Java faciliterait ce travail. Si j'écrivais un langage fonctionnel, je ne considérerais pas l'utilisation de Patterns OO.


Je voudrais ajouter deux excellents articles de Jeremy Gibbons, mais assez denses: «Les patrons de design en tant que programmes génériques de type supérieur» et «L'essence du modèle Iterator» (tous deux disponibles ici: http://www.comlab.ox.ac.uk/jeremy.gibbons/publications/ ).

Tous deux décrivent comment les constructions fonctionnelles idiomatiques couvrent le terrain couvert par des modèles de conception spécifiques dans d'autres contextes (orientés objet).


La POO et les modèles du GoF traitent avec les états. La POO modèle la réalité pour garder le code le plus proche possible des exigences de la réalité. Les modèles de conception du GoF sont des modèles qui ont été identifiés pour résoudre les problèmes du monde réel atomique. Ils gèrent le problème de l'état de manière sémantique.

Comme dans la programmation fonctionnelle réelle, aucun état n'existe, cela n'a aucun sens d'appliquer les modèles GoF. Il n'y a pas de modèles de conception fonctionnelle de la même manière que les modèles de conception du GoF. Chaque modèle de conception fonctionnelle est artificiel contrairement à la réalité car les fonctions sont des constructions de mathématiques et non de réalité.

Les fonctions manquent de notion de temps car elles retournent toujours la même valeur quel que soit l'heure actuelle, à moins que le temps ne fasse partie des paramètres de la fonction, ce qui rend vraiment difficile le traitement des «demandes futures». Les langages hybrides mélangent ces concepts qui font que les langages ne sont pas de vrais langages de programmation fonctionnels.

Les langages fonctionnels ne montent qu'à cause d'une chose: les restrictions naturelles actuelles de la physique. Les processeurs d'aujourd'hui sont limités dans leur vitesse de traitement des instructions en raison de lois physiques. Vous voyez une stagnation de la fréquence d'horloge mais une expansion dans les cœurs de traitement. C'est pourquoi le parallélisme des instructions devient de plus en plus important pour augmenter la vitesse des applications modernes. Comme la programmation fonctionnelle, par définition, n'a pas d'état et n'a donc aucun effet secondaire, il est sûr de traiter les fonctions en toute sécurité en parallèle.

Les modèles du GoF ne sont pas obsolètes. Ils sont au moins nécessaires pour modéliser les exigences du monde réel. Mais si vous utilisez un langage de programmation fonctionnel, vous devez les transformer en leurs équivalents hybrides. Enfin, vous n'avez aucune chance de créer uniquement des programmes fonctionnels si vous utilisez la persistance. Pour les éléments hybrides de votre programme, il reste la nécessité d'utiliser des modèles GoF. Tout autre élément purement fonctionnel n'est pas nécessaire pour utiliser les patterns GoF car il n'y a pas d'état.

Parce que le modèle GoF n'est pas nécessaire pour la programmation fonctionnelle réelle, cela ne signifie pas que les principes SOLID ne doivent pas être appliqués. Les principes SOLID sont au-delà de tout paradigme linguistique.


La programmation fonctionnelle ne remplace pas les modèles de conception. Les motifs de conception ne peuvent pas être remplacés.

Les modèles existent simplement; ils ont émergé au fil du temps. Le livre du GoF a formalisé certains d'entre eux. Si de nouveaux modèles apparaissent, les développeurs utilisent des langages de programmation fonctionnels, ce qui est passionnant, et il y aura peut-être aussi des livres écrits à leur sujet.


Le billet de blog que vous avez cité exagère un peu sa revendication. FP n'élimine pas le besoin de modèles de conception. Le terme "modèles de conception" n'est tout simplement pas très utilisé pour décrire la même chose dans les langages de la PF. Mais ils existent. Les langages fonctionnels ont beaucoup de règles de bonne pratique de la forme "quand vous rencontrez le problème X, utilisez le code qui ressemble à Y", qui est fondamentalement ce qu'est un modèle de conception.

Cependant, il est correct que la plupart des modèles de conception spécifiques à la POO ne sont pas pertinents dans les langages fonctionnels.

Je ne pense pas qu'il devrait être particulièrement controversé de dire que les modèles de conception en général existent seulement pour combler les lacunes dans la langue. Et si une autre langue peut résoudre le même problème trivialement, cette autre langue n'aura pas besoin d'un modèle de conception pour cela. Les utilisateurs de cette langue peuvent même ne pas être conscients que le problème existe , parce que, bien, ce n'est pas un problème dans cette langue.

Voici ce que le Gang of Four a à dire sur cette question:

Le choix du langage de programmation est important car il influence le point de vue de chacun. Nos modèles supposent des fonctionnalités de langage de niveau Smalltalk / C ++, et ce choix détermine ce qui peut et ne peut pas être implémenté facilement. Si nous supposions des langages procéduraux, nous aurions pu inclure des motifs de conception appelés «Héritage», «Encapsulation» et «Polymorphisme». De même, certains de nos modèles sont pris en charge directement par les langages orientés objet les moins courants. CLOS a des méthodes multiples, par exemple, ce qui réduit le besoin d'un modèle tel que Visitor. En fait, il existe suffisamment de différences entre Smalltalk et C ++ pour que certains modèles puissent être exprimés plus facilement dans une langue que dans l'autre. (Voir Iterator par exemple.)

(Ce qui précède est une citation de l'introduction au livre de modèles de conception, page 4, paragraphe 3)

Les principales caractéristiques de la programmation fonctionnelle comprennent des fonctions telles que des valeurs de première classe, des valeurs immuables, des valeurs immuables, etc. Il ne me semble pas évident que les modèles de conception OO se rapprochent de ces caractéristiques.

Quel est le modèle de commande, sinon une approximation des fonctions de première classe? :) Dans un langage FP, vous passeriez simplement une fonction comme argument à une autre fonction. Dans un langage OOP, vous devez encapsuler la fonction dans une classe, que vous pouvez instancier et ensuite passer cet objet à l'autre fonction. L'effet est le même, mais dans la POO, cela s'appelle un motif de conception, et il faut beaucoup plus de code. Et quel est le modèle d'usine abstraite, sinon en cours? Transmettez les paramètres à une fonction un peu à la fois, pour configurer le type de valeur qu'il recrache lorsque vous l'appelez enfin.

Alors oui, plusieurs modèles de conception du GoF sont rendus redondants dans les langages FP, car des alternatives plus puissantes et plus faciles à utiliser existent.

Mais bien sûr, il existe encore des modèles de conception qui ne sont pas résolus par les langages de FP. Quel est l'équivalent FP d'un singleton? (Sans tenir compte pour un moment que les singletons sont généralement un modèle terrible à utiliser)

Et cela fonctionne dans les deux sens aussi. Comme je l'ai dit, FP a aussi ses modèles de conception, les gens ne les considèrent généralement pas comme tels.

Mais vous avez peut-être couru à travers les monades. Quels sont-ils, sinon un modèle de conception pour "traiter avec l'état global"? C'est un problème si simple dans les langages OOP qu'il n'y a pas de modèle de conception équivalent.

Nous n'avons pas besoin d'un modèle de conception pour "incrémenter une variable statique", ou "lire depuis cette socket", parce que c'est exactement ce que vous faites .

Dans les langages fonctionnels (purs), les effets secondaires et l'état mutable sont impossibles, à moins que vous ne l'utilisiez avec le "motif de conception" de la monade, ou l'une quelconque des autres méthodes permettant la même chose.

De plus, dans les langages fonctionnels qui supportent la POO (tels que F # et OCaml), il me semble évident que les programmeurs utilisant ces langages utiliseraient les mêmes modèles de conception que ceux disponibles pour tous les autres langages POO. En fait, actuellement, j'utilise F # et OCaml tous les jours, et il n'y a pas de différences frappantes entre les modèles que j'utilise dans ces langues et les modèles que j'utilise lorsque j'écris en Java.

Peut-être parce que vous pensez toujours impérativement? Beaucoup de gens, après avoir traité des langues impératives toute leur vie, ont du mal à abandonner cette habitude quand ils essaient un langage fonctionnel. (J'ai vu quelques tentatives assez amusantes à F #, où littéralement chaque fonction était juste une chaîne d'instructions 'let', comme si vous aviez pris un programme C, et remplacé tous les points-virgules par 'let'. :))

Mais une autre possibilité pourrait être que vous n'avez tout simplement pas réalisé que vous résolvez les problèmes de manière triviale, ce qui nécessiterait des modèles de conception dans un langage OOP.

Lorsque vous utilisez currying, ou passez une fonction comme argument à un autre, arrêtez-vous et réfléchissez à la façon dont vous le feriez dans un langage OOP.

Existe-t-il une vérité à l'affirmation selon laquelle la programmation fonctionnelle élimine le besoin de modèles de conception OOP?

Oui. :) Lorsque vous travaillez dans un langage FP, vous n'avez plus besoin des modèles de conception spécifiques à la POO. Mais vous avez toujours besoin de modèles de conception généraux, tels que MVC ou d'autres éléments non spécifiques à la POO, et vous avez besoin de quelques nouveaux "modèles de conception" spécifiques à FP à la place. Toutes les langues ont leurs défauts, et les modèles de conception sont généralement comment nous travaillons autour d'eux.

Quoi qu'il en soit, vous trouverez peut-être intéressant de vous initier aux langages FP "plus propres", comme ML (mon préféré, au moins à des fins d'apprentissage), ou Haskell, où vous n'avez pas besoin de la béquille OOP quand vous sommes confrontés à quelque chose de nouveau.

Comme prévu, quelques personnes se sont opposées à ma définition des schémas de design comme «réparer les défauts dans une langue», alors voici ma justification: Comme déjà dit, la plupart des modèles de conception sont spécifiques à un paradigme de programmation ou parfois même un langage spécifique. Souvent, ils résolvent des problèmes qui n'existent que dans ce paradigme (voir monades pour FP, ou les usines abstraites pour POO). Pourquoi le modèle d'usine abstraite n'existe-t-il pas dans FP? Parce que le problème qu'il essaie de résoudre n'existe pas là. Ainsi, si un problème existe dans les langages POO, qui n'existe pas dans les langages FP, il est clair que cela constitue une lacune des langages POO. Le problème peut être résolu, mais votre langage ne le fait pas, mais nécessite un tas de code standard de votre part pour contourner ce problème. Idéalement, nous aimerions que notre langage de programmation fasse disparaître tous les problèmes par magie. Tout problème qui existe encore est en principe une lacune de la langue. ;)


Les commentaires de Brian sur le lien étroit entre le langage et le modèle sont justes,

La partie manquante de cette discussion est le concept d'idiome. Le livre de Coplien, "Advanced C ++" a eu une énorme influence ici. Longtemps avant qu'il ne découvre Christopher Alexander et la Colonne sans nom (et vous ne pouvez pas parler des modèles sans lire Alexander non plus), il a parlé de l'importance de maîtriser l'idiome en apprenant vraiment une langue. Il a utilisé la copie de chaîne en C comme exemple, tandis que (* de ++ = * à ++); Vous pouvez le voir comme un bandaid pour un élément de langage manquant (ou une fonction de bibliothèque), mais ce qui compte vraiment, c'est que c'est une unité de pensée ou d'expression plus grande que n'importe laquelle de ses parties.

C'est ce que tentent de faire les schémas et les langages pour nous permettre d'exprimer nos intentions plus succinctement. Plus les unités de pensée sont riches, plus les pensées que vous pouvez exprimer sont complexes. Avoir un vocabulaire riche et partagé à plusieurs échelles - de l'architecture du système à la manipulation des bits - nous permet d'avoir des conversations plus intelligentes et des réflexions sur ce que nous devrions faire.

Nous pouvons aussi, en tant qu'individus, apprendre. Quel est le point entier de l'exercice. Nous pouvons chacun comprendre et utiliser des choses que nous ne serions jamais capables de penser à nous-mêmes. Les langues, les cadres, les bibliothèques, les modèles, les idiomes, etc. ont tous leur place dans le partage de la richesse intellectuelle.


Les modèles de conception du GoF codent des solutions de contournement pour les langages OO qui sont des descendants de Simula 67, comme Java et C ++.

La plupart des "maux" traités par les modèles de conception sont causés par:

  • les classes typées statiquement, qui spécifient des objets mais ne sont pas elles-mêmes des objets;
  • restriction à l'envoi unique (seul l'argument le plus à gauche est utilisé pour sélectionner une méthode, les arguments restants sont considérés comme des types statiques seulement: s'ils ont des types dynamiques, c'est à la méthode de le trier avec des approches ad-hoc);
  • distinction entre les appels de fonctions régulières et les appels de fonctions orientés objet, ce qui signifie que les fonctions orientées objet ne peuvent pas être transmises en tant qu'arguments fonctionnels où des fonctions régulières sont attendues et vice versa; et
  • distinction entre "types de base" et "types de classe".

Il n'y a pas un seul de ces modèles de conception qui ne disparaît pas dans le système d'objets Common Lisp, même si la solution est structurée essentiellement de la même manière que dans le modèle de conception correspondant. (De plus, ce système d'objets précède de loin le livre du GoF depuis plus de dix ans et Common Lisp est devenu une norme ANSI la même année que la publication de ce livre.)

En ce qui concerne la programmation fonctionnelle, la question de savoir si les modèles s'appliquent ou non dépend du fait que le langage de programmation fonctionnel donné possède une sorte de système objet et s'il est modélisé après les systèmes objet qui bénéficient des motifs. Ce type d'orientation d'objet ne se mélange pas bien avec la programmation fonctionnelle, car la mutation de l'état est au premier plan et au centre.

La construction et l'accès non-mutant sont compatibles avec la programmation fonctionnelle, et donc les schémas qui ont trait à l'accès abstrait ou à la construction pourraient être applicables: modèles comme Usine, Façade, Proxy, Décorateur, Visiteur.

D'un autre côté, les modèles de comportement tels que l'état et la stratégie ne s'appliquent probablement pas directement à la POO fonctionnelle, car la mutation de l'état est au cœur de celle-ci. Cela ne signifie pas qu'ils ne s'appliquent pas; peut-être qu'ils s'appliquent d'une manière ou d'une autre en combinaison avec les astuces disponibles pour simuler un état mutable.


Lorsque vous essayez de regarder cela au niveau des «modèles de conception» (en général) et de «FP versus OOP», les réponses que vous trouverez seront au mieux obscures.

Aller un niveau plus profond sur les deux axes, cependant, et d'examiner des modèles de conception spécifiques et des caractéristiques linguistiques spécifiques et les choses deviennent plus claires.

Par exemple, certains modèles spécifiques, comme Visitor , Strategy , Command et Observer, changent ou disparaissent définitivement lorsque vous utilisez un langage avec des types de données algébriques et des correspondances de motifs , des fermetures , des fonctions de première classe , etc. "restez", cependant.

En général, je dirais que, au fil du temps, les modèles spécifiques sont éliminés par de nouvelles caractéristiques du langage (ou simplement de la popularité croissante). C'est le cours naturel de la conception de la langue; Au fur et à mesure que les langues deviennent de plus haut niveau, les abstractions qui auparavant ne pouvaient être mentionnées que dans un livre en utilisant des exemples deviennent maintenant des applications d'une caractéristique ou d'une bibliothèque particulière.

(À part: voici un blog récent que j'ai écrit, qui contient d'autres liens vers d'autres discussions sur les modèles de PF et de design.)


OOP et FP ont des objectifs différents, OOP vise à encapsuler les complexités / parties mobiles des composants logiciels et FP vise à minimiser la complexité et les dépendances des composants logiciels mais ces 2 paradigmes ne sont pas nécessairement contradictoires à 100% et pourraient être appliqués ensemble pour obtenir le bénéfice des deux mondes. Même avec un langage qui ne supporte pas nativement la programmation fonctionnelle comme C #, vous pouvez écrire du code fonctionnel si vous comprenez les principes FP, de même vous pouvez appliquer les principes PO en utilisant F # si vous comprenez les principes, les modèles et les meilleures pratiques. Vous feriez le bon choix en fonction de la situation et du problème que vous essayez de résoudre, quel que soit le langage de programmation que vous utilisez.


Vous ne pouvez pas avoir cette discussion sans mettre en place des systèmes de type.

Les principales caractéristiques de la programmation fonctionnelle comprennent des fonctions telles que des valeurs de première classe, des valeurs immuables, des valeurs immuables, etc. Il ne me semble pas évident que les modèles de conception OO se rapprochent de ces caractéristiques.

C'est parce que ces fonctionnalités ne traitent pas les mêmes problèmes que la POO ... elles sont des alternatives à la programmation impérative. La réponse de FP à OOP réside dans les systèmes de types de ML et Haskell ... en particulier les types de somme, les types de données abstraits, les modules ML, les classes de type Haskell.

Mais bien sûr, il existe encore des modèles de conception qui ne sont pas résolus par les langages de FP. Quel est l'équivalent FP d'un singleton? (Sans tenir compte pour un moment que les singletons sont généralement un modèle terrible à utiliser)

La première chose que fait typeclasses est d'éliminer le besoin de singletons.

Vous pourriez passer par la liste des 23 et éliminer plus, mais je n'ai pas le temps de le faire maintenant.






functional-programming