¿Por qué un modelo de dominio anémico se considera malo en C # / OOP, pero muy importante en F # / FP?

43

En una publicación de blog sobre F # por diversión y beneficio, dice:

  

En un diseño funcional, es muy importante separar el comportamiento de   datos. Los tipos de datos son simples y "tontos". Y luego por separado, tu   tiene una serie de funciones que actúan sobre esos tipos de datos.

     

Esto es exactamente lo contrario de un diseño orientado a objetos, donde   El comportamiento y los datos están destinados a ser combinados. Después de todo, eso es exactamente   que clase es En un diseño verdaderamente orientado a objetos, de hecho, deberías   no tiene más que comportamiento, los datos son privados y solo pueden ser   Se accede a través de métodos.

     

De hecho, en OOD, no tener suficiente comportamiento alrededor de un tipo de datos es   considerado una Cosa Mala, e incluso tiene un nombre: el " dominio anémico   modelo ".

Dado que en C # parece que seguimos tomando préstamos de F # y tratando de escribir un código de estilo más funcional; ¿por qué no tomamos prestada la idea de separar datos / comportamiento e incluso la consideramos mala? ¿Es simplemente que la definición no coincide con OOP, o hay una razón concreta por la cual es malo en C # que por alguna razón no se aplica en F # (y de hecho, se invierte)?

(Nota: estoy especialmente interesado en las diferencias en C # / F # que podrían cambiar la opinión de lo que es bueno / malo, en lugar de las personas que pueden estar en desacuerdo con cualquier opinión en la publicación del blog).

    
pregunta Danny Tuppeny 28.06.2013 - 19:02

3 respuestas

37

La razón principal por la que FP apunta a esto y C # OOP no lo hace es que en FP la atención se centra en la transparencia referencial; es decir, los datos entran en una función y los datos salen, pero los datos originales no se modifican.

En C # OOP hay un concepto de delegación de responsabilidad en el que le delegas la administración de un objeto y, por lo tanto, quieres que cambie sus propios elementos internos.

En FP, nunca quieres cambiar los valores de un objeto, por lo tanto, tener las funciones incrustadas en tu objeto no tiene sentido.

Además, en FP, tienes un polimorfismo de tipo más alto que permite que tus funciones sean mucho más generalizadas de lo que permite C # OOP. De esta manera, puede escribir una función que funcione para cualquier a , y por lo tanto, tenerla incrustada en un bloque de datos no tiene sentido; eso acoplaría el método de manera que solo funcione con ese tipo en particular de a . Este tipo de comportamiento es bueno y común en C # OOP porque no tienes la capacidad de abstraer funciones, por lo general, de todos modos, pero en FP es una compensación.

El mayor problema que he visto en los modelos de dominios anémicos en C # OOP es que terminas con un código duplicado porque tienes DTO x, y 4 funciones diferentes que comprometen la actividad f con DTO x porque 4 personas diferentes no vieron La otra implementación. Cuando pones el método directamente en DTO x, entonces esas 4 personas ven la implementación de f y la reutilizan.

Los modelos de datos anémicos en C # OOP dificultan la reutilización del código, pero este no es el caso en FP porque una sola función se generaliza en tantos tipos diferentes que se obtiene una mayor reutilización del código ya que esa función se puede usar en muchos más escenarios que una función que escribirías para un solo DTO en C #.

Como señalado en los comentarios , la inferencia de tipos es uno de los beneficios en los que confía FP para permitir un polimorfismo tan significativo, y específicamente puede rastrear esto hasta el Sistema de tipo Hindley Milner con inferencia de tipo Algoritmo W; este tipo de inferencia en el sistema de tipo C # OOP se evitó porque el tiempo de compilación cuando se agrega la inferencia basada en restricciones se vuelve extremadamente largo debido a la búsqueda exhaustiva necesaria, detalles aquí: enlace

    
respondido por el Jimmy Hoffa 28.06.2013 - 19:22
5
  

¿Por qué un modelo de dominio anémico se considera malo en C # / OOP, pero muy importante en F # / FP?

Su pregunta tiene un gran problema que limitará la utilidad de las respuestas que obtiene: está implicando / asumiendo que F # y FP son similares. FP es una gran familia de idiomas que incluye la reescritura de términos simbólicos, dinámicos y estáticos. Incluso entre los lenguajes FP tipificados estáticamente, hay muchas tecnologías diferentes para expresar modelos de dominio, como los módulos de orden superior en OCaml y SML (que no existen en F #). F # es uno de estos lenguajes funcionales, pero es particularmente notable por ser lean y, en particular, no proporciona módulos de orden superior ni tipos de clase superior.

De hecho, no podría comenzar a decirle cómo se expresan los modelos de dominio en FP. La otra respuesta aquí habla muy específicamente sobre cómo se hace en Haskell y no se aplica en absoluto a Lisp (la madre de todos los idiomas de FP), la familia de idiomas de ML o cualquier otro idioma funcional.

  

¿por qué no tomamos prestada la idea de separar datos / comportamiento e incluso la consideramos mala?

Los genéricos podrían considerarse una forma de separar datos y comportamientos. Los genéricos provienen de la familia ML de lenguajes de programación funcionales que no son parte de OOP. C # tiene genéricos, por supuesto. Por lo tanto, se podría argumentar que C # está tomando lentamente la idea de separar datos y comportamientos.

  

Es simplemente que la definición no se ajusta a la POO,

Creo que la POO se basa en una premisa fundamentalmente diferente y, en consecuencia, no le brinda las herramientas que necesita para separar los datos y el comportamiento. Para todos los propósitos prácticos, necesita productos y datos de suma y despacho sobre ellos. En ML, esto significa unión y tipos de registro y coincidencia de patrones.

Consulte el ejemplo que di aquí .

  ¿

o hay una razón concreta por la cual es malo en C # que por alguna razón no se aplica en F # (y de hecho, se invierte)?

Tenga cuidado al saltar de OOP a C #. C # no es tan puritano en cuanto a la POO como en otros idiomas. .NET Framework ahora está lleno de genéricos, métodos estáticos e incluso lambdas.

  

(Nota: estoy especialmente interesado en las diferencias en C # / F # que podrían cambiar la opinión de lo que es bueno / malo, en lugar de las personas que pueden estar en desacuerdo con cualquier opinión en la publicación del blog).

La falta de tipos de unión y coincidencia de patrones en C # hace que sea casi imposible hacerlo. Cuando todo lo que tienes es un martillo, todo parece un clavo ...

    
respondido por el Jon Harrop 16.03.2015 - 13:24
-4

Creo que en una aplicación de negocios a menudo no desea ocultar datos porque la coincidencia de patrones en valores inmutables es excelente para garantizar que cubre todos los casos posibles. Pero si está implementando algoritmos complejos o estructuras de datos, es mejor que oculte los detalles de implementación convirtiendo los ADT (tipos de datos algebraicos) en ADT (tipos de datos abstractos).

    
respondido por el Giacomo Citi 04.11.2015 - 18:04

Lea otras preguntas en las etiquetas