Diseño en lenguajes "mixtos": ¿diseño orientado a objetos o programación funcional?


11

En los últimos años, los idiomas que me gusta usar se están volviendo cada vez más "funcionales". Ahora uso lenguajes que son una especie de "híbrido": C #, F #, Scala. Me gusta diseñar mi aplicación usando clases que corresponden a los objetos del dominio, y usar características funcionales donde esto hace que la codificación sea más fácil, más coincidente y más segura (especialmente cuando se opera en colecciones o cuando se pasan funciones).

Sin embargo, los dos mundos "chocan" cuando se trata de diseñar patrones. El ejemplo específico que enfrenté recientemente es el patrón Observador. Quiero que un productor notifique algún otro código (los "consumidores / observadores", digamos un almacenamiento de base de datos, un registrador, etc.) cuando se crea o cambia un elemento.

Inicialmente lo hice "funcionalmente" así:

producer.foo(item => { updateItemInDb(item); insertLog(item) })
// calls the function passed as argument as an item is processed

Pero ahora me pregunto si debería usar un enfoque más "OO":

interface IItemObserver {
  onNotify(Item)
}
class DBObserver : IItemObserver ...
class LogObserver: IItemObserver ...

producer.addObserver(new DBObserver)
producer.addObserver(new LogObserver)
producer.foo() //calls observer in a loop

¿Cuáles son las ventajas y desventajas de los dos enfoques? Una vez escuché a un gurú de FP decir que los patrones de diseño están ahí solo por las limitaciones del lenguaje, y es por eso que hay tan pocos en los lenguajes funcionales. Tal vez esto podría ser un ejemplo de ello?

EDITAR: En mi caso particular, no lo necesito, pero ... ¿cómo implementaría la eliminación y la adición de "observadores" de manera funcional? (Es decir, ¿cómo implementaría todas las funcionalidades en el patrón?) ¿Simplemente pasando una nueva función, por ejemplo?


¿Qué hay de los actores?
Kiritsuku

Olvídate de las clases y todas esas cosas inútiles. Es mejor que piense en términos de módulos (consulte los idiomas SML y OCaml para obtener inspiración).
SK-logic

@Antoras Si pudieras hacer una comparación con un enfoque basado en actores, sería más que bienvenido :)
Lorenzo Dematté

2
@ dema80, OCaml es perfectamente multi-paradigma. Los módulos no están relacionados con la programación funcional en absoluto. Hay un sistema de módulos avanzado en un Ada puramente imperativo, por ejemplo. Y toda la fama OOP ganada debería ir realmente a los módulos: todo lo bueno de OOP es solo varias formas de simular la funcionalidad de los módulos. Puede olvidarse por completo de todas esas clases y utilizar su sintaxis para expresar módulos, pensando en términos de módulos, no de POO. Por cierto, eso es exactamente lo que hizo Microsoft con su mscorlib: no hay mucha POO allí, solo módulos y espacios de nombres.
SK-logic

1
Creo que la mejor pregunta es "¿Hay alguna claridad u organización que pierdes al hacerlo de la manera FP?"
djechlin

Respuestas:


0

Ese es un buen ejemplo de dos enfoques diferentes que llevan la noción de realizar una tarea fuera del límite de interés para el objeto que llama.

Si bien está claro en este ejemplo que debe optar por el enfoque funcional, en general dependerá realmente de cuán complejo sea el comportamiento que debe exhibir el objeto llamado. Si realmente se trata de un comportamiento complejo, donde se encontrará reaplicando lógica similar a menudo, y los generadores de funciones no se pueden usar para expresarlo claramente, entonces probablemente querrá ir a la composición o herencia de la clase, donde tener un poco más de libertad para reutilizar y ampliar el comportamiento existente de forma ad-hoc.

Sin embargo, un patrón que sí observé es que, por lo general, los desarrolladores adoptan el enfoque funcional inicialmente y solo una vez que surge la demanda de un comportamiento más granular, deciden optar por un enfoque basado en la clase. Sé, por ejemplo, que Django pasó de vistas basadas en funciones, cargadores de plantillas y corredores de pruebas a las basadas en clases una vez que los beneficios y requisitos se hicieron evidentes, pero no antes de eso.


Creo que esta respuesta está un poco equivocada. La programación funcional no es programación (solo con) funciones. La programación funcional también usa abstracciones, por lo que no hay dicotomía aquí.
Doval

"composición o herencia, donde tendrás un poco más de libertad para reutilizar y ampliar el comportamiento existente" estás hablando así. NO ES uno de los principales beneficios de la PF pura. modularidad, del composability y reuseability sólo ocurre de forma natural cuando código funcionalmente, esto no es una "cosa programación orientada a objetos"
Sara

@ FilipDupanović Me refería a reutilizar y ampliar el código existente. Las funciones puras son probablemente las cosas más componibles en toda la programación. estás escrito como si no pudieras manejar la complejidad en un entorno funcional puro. gestionar la complejidad al componer partes simples en partes más grandes pero aún simples y opacas es todo el núcleo de FP, y muchos dirían que es incluso mucho mejor que OOP. No estoy de acuerdo con la dicotomía entre "frases ingeniosas funcionales que no escalan VS POO sólido que no escalan ningún problema" que planteaste.
sara

Usted dijo que FP era inferior cuando se trata de componer y reutilizar código, y que cuando las aplicaciones se vuelven más complejas, OOP será más o menos siempre "mejor". Afirmo que esto es simplemente falso y engañoso, por lo que pensé que justificaba un voto negativo. ¿Es eso realmente "fanatismo purista"? Sin embargo, no discutiré esto más aquí ya que los comentarios no son para discusiones extendidas como estas.
sara

5

La versión funcional es mucho más corta, más fácil de mantener, más fácil de leer y, en general, muy superior en casi todos los aspectos imaginables.

Muchos, aunque lejos de todos, los patrones son para compensar la falta de características en POO, como los Observadores. Esos están mucho mejor modelados funcionalmente.


Estoy de acuerdo y tengo el mismo sentimiento.
Lorenzo Dematté

Estoy de acuerdo y tengo el mismo sentimiento. Pero estaba "haciendo trampa" con mi código funcional: en mi caso es todo lo que necesito, pero ¿qué pasa si necesito agregar y eliminar "observadores"? Edité mi pregunta
Lorenzo Dematté

5

Su "FP guru" tiene razón en parte; Muchos patrones OO son hacks para hacer cosas funcionales. (Su afirmación de que esta es la razón por la que hay pocos lenguajes FP parece dudoso en el mejor de los casos). Los patrones de Observador y Estrategia están tratando de emular funciones de primera clase. El patrón de visitante es un truco para simular la coincidencia de patrones. Tu IItemObserveres solo una función disfrazada. Pretender que es diferente de cualquier otra función que tome un artículo no te compra nada.

Los objetos son solo un tipo de abstracción de datos. Este documento ayudará a arrojar algo de luz sobre ese tema. Los objetos pueden ser útiles, pero es importante reconocer que no son apropiados para todo. No hay dicotomía; simplemente es cuestión de elegir la herramienta adecuada para el trabajo correcto, y la programación funcional de ninguna manera requiere que renuncies a los objetos. Aparte de eso, la programación funcional es más que solo usar funciones. También se trata de minimizar los efectos secundarios y la mutación.


+1 para (IMO) una buena respuesta. Además, gracias por el enlace al documento: lo había leído hace algún tiempo y luego lo perdí. Ahora lo he encontrado de nuevo.
Giorgio

-1

Realmente no puedo responder la pregunta porque no soy bueno en lenguajes funcionales; pero creo que deberías estar menos preocupado por el enfoque siempre que lo que tienes funcione. Por lo que entiendo, mientras no agregue más oyentes en el futuro o no cambie los oyentes durante la ejecución, puede omitir el patrón de Observador aquí.

No estoy de acuerdo con que los patrones de diseño compensen las "limitaciones" en los lenguajes OO. Están ahí para hacer un buen uso de las características de OOP. El polimorfismo y la herencia son características, no limitaciones. Los patrones de diseño hacen uso de estas características para promover un diseño flexible. Puede hacer un programa absolutamente no OO en un OO. Puede, con mucho cuidado, escribir un programa completo que contenga objetos que no tengan estado, imitando FP.


1
"Puede, con mucho cuidado, escribir un programa completo que contenga objetos que no tengan estado, imitando FP", por supuesto, y a través de la disciplina también puede hacer lo mismo en lenguajes imperativos. :) En general, no creo que los patrones de diseño sean algo para compensar las limitaciones, pero consideremos el caso del patrón Visitante.
Lorenzo Dematté

Además, no me preocupa el código: sin embargo, me gustaría confrontar a otros programadores en el enfoque (a mi entender, esto es para lo que son los programadores.se, de lo contrario habría publicado mi Q en SO)
Lorenzo Dematté

Cada vez que detecta un patrón repetitivo, no es más que una indicación de una limitación severa de su lenguaje y marco de modelado. No habrá patrones en absoluto en un mundo ideal.
SK-logic

@ SK-logic: Desafortunadamente, el mundo no es ideal, y el mundo real tiene patrones. Es por eso que los lenguajes OO tienen herencia, para implementar código repetible sin tener que volver a escribirlos nuevamente. Los objetos del mundo real tienen un estado, es por eso que hay un patrón de estado
DPD

1
@ SK-logic: Soy consciente de que algunos lenguajes son programables, y algunos permiten la aplicación de efectos desde el sistema de tipos también. Mi punto es que, como "OOP", "patrón" es un término tristemente incomprendido. Un patrón es algo que sigue apareciendo en formas similares pero diferentes , que no admite una solución uniforme . A veces puede hacer desaparecer esas cuasirepeticiones: los métodos múltiples hacen que el Despacho de visitante / doble sea redundante. Eso no implica "todos los patrones son signos de deficiencia", porque eso significa que el mundo real es deficiente. Los patrones se originaron en la arquitectura , no en el software.
Frank Shearar
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.