Em um post no F # por diversão e lucro, ele diz:
Em um design funcional, é muito importante separar o comportamento dos dados. Os tipos de dados são simples e "burros". E então separadamente, você tem várias funções que atuam nesses tipos de dados.
Esse é exatamente o oposto de um design orientado a objetos, onde comportamento e dados devem ser combinados. Afinal, é exatamente isso que uma classe é. De fato, em um design realmente orientado a objetos, você deve ter apenas comportamento - os dados são privados e só podem ser acessados por métodos.
De fato, em OOD, não ter comportamento suficiente em torno de um tipo de dados é considerado uma Coisa Ruim e até tem um nome: o " modelo de domínio anêmico ".
Dado que, em C #, parecemos continuar pedindo emprestado ao F # e tentando escrever um código mais funcional; por que não emprestamos a idéia de separar dados / comportamento e até consideramos ruim? É simplesmente que a definição não combina com OOP, ou há uma razão concreta para que seja ruim em C # que por alguma razão não se aplique em F # (e, de fato, é revertida)?
(Observação: 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 na publicação do blog).
fonte
Respostas:
A principal razão pela qual o FP visa isso e o C # OOP não é que, no FP, o foco está na transparência referencial; isto é, os dados entram em uma função e os dados saem, mas os dados originais não são alterados.
No C # OOP, existe um conceito de delegação de responsabilidade no qual você delega o gerenciamento de um objeto e, portanto, deseja que ele mude seus próprios internos.
No FP, você nunca deseja alterar os valores em um objeto, portanto, ter suas funções incorporadas ao seu objeto não faz sentido.
Além disso, no FP, você tem um polimorfismo de tipo mais alto, permitindo que suas funções sejam muito mais generalizadas do que o C # OOP permite. Dessa maneira, você pode escrever uma função que funcione para qualquer um
a
, e, portanto, incorporá-la em um bloco de dados não faz sentido; isso uniria fortemente o método para que ele funcione apenas com esse tipo específico dea
. Um comportamento como esse é muito comum no C # OOP porque você não tem a capacidade de abstrair funções de maneira geral, mas no FP é uma desvantagem.O maior problema que eu já vi nos modelos de domínio anêmico no C # OOP é que você acaba com código duplicado porque possui o DTO x e 4 funções diferentes que confirmam a atividade f para o DTO x, porque quatro pessoas diferentes não viram a outra implementação . Quando você coloca o método diretamente no DTO x, todas essas 4 pessoas veem a implementação de f e a reutilizam.
Modelos de dados anêmicos no C # OOP dificultam a reutilização de código, mas esse não é o caso no FP porque uma única função é generalizada em tantos tipos diferentes que você obtém uma maior reutilização de código, pois essa função é utilizável em muitos outros cenários do que uma função que você escreveria para um único DTO em C #.
Conforme apontado nos comentários , a inferência de tipo é um dos benefícios que a FP utiliza para permitir esse polimorfismo significativo e, especificamente, você pode rastrear isso no sistema de tipo Hindley Milner com a inferência de tipo W do algoritmo; essa inferência de tipo no sistema de tipo C # OOP foi evitada porque o tempo de compilação quando a inferência baseada em restrição é adicionada se torna extremamente longo devido à pesquisa exaustiva necessária, detalhes aqui: https://stackoverflow.com/questions/3968834/generics-why -cant-o-compilador-inferir-o-tipo-argumentos-neste caso
fonte
Sua pergunta tem um grande problema que limitará a utilidade das respostas que você obtém: você está implicando / assumindo que F # e FP são semelhantes. FP é uma família enorme de idiomas, incluindo reescrita simbólica de termos, dinâmica e estática. Mesmo entre as linguagens FP estaticamente tipadas, existem muitas tecnologias diferentes para expressar modelos de domínio, como módulos de ordem superior no OCaml e SML (que não existem no F #). O 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 de tipo superior.
De fato, não pude começar a dizer como os modelos de domínio são expressos no FP. A outra resposta aqui fala muito especificamente sobre como isso é feito em Haskell e não é aplicável ao Lisp (a mãe de todas as línguas FP), à família de línguas ML ou a qualquer outra linguagem funcional.
Os genéricos podem ser considerados uma maneira de separar dados e comportamento. Os genéricos são da família ML das linguagens de programação funcional que não fazem parte do POO. C # tem genéricos, é claro. Então, alguém poderia argumentar que o C # está emprestando lentamente a idéia de separar dados e comportamento.
Acredito que a OOP se baseia em uma premissa fundamentalmente diferente e, consequentemente, não fornece as ferramentas necessárias para separar dados e comportamento. Para todos os fins práticos, você precisa de tipos de dados de produtos e soma e enviá-los por eles. No ML, isso significa tipos de união e registro e correspondência de padrões.
Confira o exemplo que dei aqui .
Cuidado ao pular de OOP para C #. O C # não é nem de longe tão puritano em relação ao OOP quanto em outros idiomas. O .NET Framework agora está cheio de genéricos, métodos estáticos e até lambdas.
A falta de tipos de união e correspondência de padrões no C # torna quase impossível fazer isso. Quando tudo que você tem é um martelo, tudo parece um prego ...
fonte
Eu acho que em um aplicativo de negócios muitas vezes você não deseja ocultar dados porque a correspondência de padrões em valores imutáveis é excelente para garantir que você esteja cobrindo todos os casos possíveis. Porém, se você estiver implementando algoritmos ou estruturas de dados complexos, é melhor ocultar os detalhes da implementação, transformando ADTs (tipos de dados algébricos) em ADTs (tipos de dados abstratos).
fonte