Por que um modelo de domínio anêmico é considerado ruim em C # / OOP, mas é muito importante em F # / FP?

43

Em uma postagem no blog em F # para se divertir e lucrar, ele diz:

In a functional design, it is very important to separate behavior from data. The data types are simple and "dumb". And then separately, you have a number of functions that act on those data types.

This is the exact opposite of an object-oriented design, where behavior and data are meant to be combined. After all, that's exactly what a class is. In a truly object-oriented design in fact, you should have nothing but behavior -- the data is private and can only be accessed via methods.

In fact, in OOD, not having enough behavior around a data type is considered a Bad Thing, and even has a name: the "anemic domain model".

Dado que em C # parecemos continuar tomando emprestado de F # e tentando escrever mais código de estilo funcional; por que não estamos tomando emprestada a ideia de separar dados / comportamento e até mesmo considerá-lo ruim? É simplesmente que a definição não com OOP, ou há uma razão concreta que é ruim em C # que, por algum motivo, não se aplica em F # (e, na verdade, é invertida)?

(Nota: estou especificamente interessado nas diferenças em C # / F # que podem mudar a opinião do que é bom / ruim, em vez de indivíduos que podem discordar de qualquer opinião no post do blog).

    
por Danny Tuppeny 28.06.2013 / 19:02
fonte

3 respostas

37

O motivo principal pelo qual o PF aponta para isso e o C # OOP não é que no PF o foco é na transparência referencial; ou seja, os dados entram em uma função e os dados são exibidos, mas os dados originais não são alterados.

Em C # OOP existe um conceito de delegação de responsabilidade no qual você delega o gerenciamento de um objeto e, portanto, deseja que ele altere seus próprios internos.

No FP você nunca quer mudar os valores em um objeto, portanto, ter suas funções incorporadas em seu objeto não faz sentido.

Além disso, no FP você tem um polimorfismo mais elevado, permitindo que suas funções sejam muito mais generalizadas do que o C # OOP permite. Desta forma, você pode escrever uma função que funciona para qualquer a e, portanto, tê-la incorporada em um bloco de dados não faz sentido; isso uniria o método de modo que funcionasse apenas com esse tipo específico de a . Comportamento como esse é muito bom e comum em C # OOP, porque você não tem a capacidade de abstrair funções de modo geral, mas em FP é uma desvantagem.

O maior problema que vi em modelos de domínio anêmico em C # OOP é que você acaba com código duplicado porque tem DTO x e 4 funções diferentes que confirmam atividade f para DTO x porque 4 pessoas diferentes não viram a outra implementação. Quando você coloca o método diretamente no DTO x, essas 4 pessoas vêem a implementação de f e a reutilizam.

Modelos de dados anêmicos em C # OOP impedem a reutilização de código, mas este não é o caso em FP porque uma única função é generalizada em tantos tipos diferentes que você obtém maior reutilização de código, já que essa função pode ser usada em muitos mais cenários uma função que você escreveria para um único DTO em C #.

Como apontada nos comentários , a inferência de tipos é um dos benefícios que o FP depende de permitir um polimorfismo tão significativo, e especificamente você pode rastrear isso de volta para o sistema de tipo Hindley Milner com inferência de tipo Algoritmo W; Essa inferência de tipo no sistema de tipo OOP C # foi evitada porque o tempo de compilação quando a inferência baseada em restrição é adicionada torna-se extremamente longo devido à pesquisa exaustiva necessária, detalhes aqui: link

    
por 28.06.2013 / 19:22
fonte
5

Why is an anemic domain model considered bad in C#/OOP, but very important in F#/FP?

Sua pergunta tem um grande problema que limitará a utilidade das respostas: você está implicando / assumindo que F # e FP são semelhantes. FP é uma enorme família de linguagens, incluindo reescrita simbólica, dinâmica e estática. Mesmo entre as linguagens FP com tipagem estática, existem muitas tecnologias diferentes para expressar modelos de domínio, como módulos de ordem superior em OCaml e SML (que não existem em F #). F # é uma dessas linguagens funcionais, mas é particularmente notável por ser enxuta e, em particular, não fornece módulos de ordem superior ou tipos mais sofisticados.

Na verdade, eu não pude começar a dizer como os modelos de domínio são expressos em FP. A outra resposta aqui fala muito especificamente sobre como é feito em Haskell e não é de todo aplicável a Lisp (a mãe de todas as linguagens FP), a família ML de linguagens ou quaisquer outras linguagens funcionais.

how come we're not borrowing the idea of separating data/behavior, and even consider it bad?

Os genéricos podem ser considerados uma maneira de separar dados e comportamento. Os genéricos provenientes da família ML de linguagens de programação funcionais não fazem parte da OOP. C # tem genéricos, é claro. Assim, pode-se argumentar que o C # está lentamente tomando emprestada a ideia de separar dados e comportamento.

Is it simply that the definition doesn't fit with OOP,

Acredito que a OOP é baseada em uma premissa fundamentalmente diferente e, consequentemente, não fornece as ferramentas necessárias para separar dados e comportamento. Para todos os efeitos práticos, você precisa de tipos de dados de produto e soma e despachá-los. Em ML, isso significa tipos de união e registro e correspondência de padrões.

Confira o exemplo que dei aqui .

or is there a concrete reason that it's bad in C# that for some reason doesn't apply in F# (and in fact, is reversed)?

Tenha cuidado ao saltar de OOP para C #. C # não é nem de longe tão puritano quanto a OOP como outras linguagens. O .NET Framework agora está cheio de genéricos, métodos estáticos e até lambdas.

(Note: I'm specifically interested in the differences in C#/F# that could change the opinion of what is good/bad, rather than individuals that may disagree with either opinion in the blog post).

A falta de tipos de união e correspondência de padrões no C # torna isso quase impossível. Quando tudo que você tem é um martelo, tudo parece um prego ...

    
por 16.03.2015 / 13:24
fonte
-4

Acho que em um aplicativo de negócios você geralmente não quer ocultar dados porque a correspondência de padrões em valores imutáveis é ótima para garantir que você esteja cobrindo todos os casos possíveis. Mas se você estiver implementando algoritmos complexos ou estruturas de dados, é melhor ocultar os detalhes da implementação transformando os ADTs (tipos de dados algébricos) em ADTs (tipos de dados abstratos).

    
por 04.11.2015 / 18:04
fonte