Às vezes, os idiomas OO podem ser usados no lugar dos idiomas de baixo nível para interagir diretamente com uma máquina. C ++ Com certeza, mas mesmo para C # existem adaptadores e afins. Embora escrever código para controlar peças mecânicas e ter controle minucioso da memória seja mantido o mais próximo possível do nível mais baixo possível. Mas se esta pergunta está relacionada ao software orientado a objetos atual, como linha de negócios, aplicativos da Web, IOT, serviços da Web e a maioria dos aplicativos usados em massa, então ...
Resposta, se aplicável
Os leitores podem tentar trabalhar com uma Arquitetura Orientada a Serviços (SOA). Ou seja, DDD, N-Camada, N-Camada, Hexagonal, qualquer que seja. Não vi um aplicativo de negócios grande usar eficientemente o OO "tradicional" (Active-Record ou Rich-Models), conforme descrito nas décadas de 70 e 80 na última década. (Ver nota 1)
A falha não está no OP, mas há alguns problemas com a pergunta.
O exemplo que você fornece é simplesmente demonstrar polimorfismo, não é um código de produção. Às vezes, exemplos exatamente assim são tomados literalmente.
No FP e SOA, os dados são separados da lógica de negócios. Ou seja, Data e Logic não andam juntos. A lógica entra em Serviços e os Dados (Modelos de Domínio) não têm comportamento polimórfico (consulte a Nota 2).
Serviços e funções podem ser polimórficos. No FP, você passa funções como parâmetros para outras funções, em vez de valores. Você pode fazer o mesmo nos idiomas OO com tipos como Callable ou Func, mas ele não funciona de forma desenfreada (consulte a Nota 3). No FP e SOA, seus modelos não são polimórficos, apenas seus serviços / funções. (Ver nota 4)
Há um caso de codificação incorreta nesse exemplo. Não estou falando apenas da corda vermelha "latidos de cachorro". Também estou falando sobre o próprio CatModel e DogModel. O que acontece quando você deseja adicionar uma ovelha? Você precisa entrar no seu código e criar um novo código? Por quê? No código de produção, eu preferiria ver apenas um AnimalModel com suas propriedades. Na pior das hipóteses, um AmphibianModel e um FowlModel se suas propriedades e manipulação forem muito diferentes.
Isso é o que eu esperaria ver no atual idioma "OO":
public class Animal
{
public int AnimalID { get; set; }
public int LegCount { get; set; }
public string Name { get; set; }
public string WhatISay { get; set; }
}
public class AnimalService : IManageAnimals
{
private IPersistAnimals _animalRepo;
public AnimalService(IPersistAnimals animalRepo) { _animalRepo = animalRepo; }
public List<Animal> GetAnimals() => _animalRepo.GetAnimals();
public string WhatDoISay(Animal animal)
{
if (!string.IsNullOrWhiteSpace(animal.WhatISay))
return animal.WhatISay;
return _animalRepo.GetAnimalNoise(animal.AnimalID);
}
}
Como você muda de Classes em OO para Programação Funcional? Como outros já disseram; Você pode, mas na verdade não. O objetivo do exposto acima é demonstrar que você nem deveria usar Classes (no sentido tradicional do mundo) ao executar Java e C #. Depois de escrever o código em uma arquitetura orientada a serviços (DDD, em camadas, em camadas, hexagonal, qualquer que seja), você estará um passo mais perto do Functional porque separa seus dados (modelos de domínio) das funções lógicas (serviços).
OO Language um passo mais perto do FP
Você pode ir um pouco mais longe e dividir seus serviços SOA em dois tipos.
Classe opcional tipo 1 : Serviços comuns de implementação de interface para pontos de entrada. Estes seriam pontos de entrada "impuros" que podem chamar outras funcionalidades "Puras" ou "Impuras". Podem ser seus pontos de entrada de uma API RESTful.
Classe opcional tipo 2 : serviços puros de lógica comercial. Essas são classes estáticas que possuem a funcionalidade "pura". No FP, "Puro" significa que não há efeitos colaterais. Ele não define explicitamente Estado ou Persistência em lugar algum. (Ver nota 5)
Portanto, quando você pensa em Classes em Linguagens Orientadas a Objetos, sendo usadas em uma Arquitetura Orientada a Serviços, ele não apenas beneficia seu Código OO, mas também começa a tornar a Programação Funcional muito fácil de entender.
Notas
Nota 1 : O design orientado a objeto "Rich" ou "Active-Record" original ainda existe. Há MUITO código legado assim quando as pessoas estavam "fazendo o certo" há uma década ou mais. A última vez que vi esse tipo de código (feito corretamente) era de um videogame Codebase em C ++, onde eles controlavam a memória com precisão e tinham um espaço muito limitado. Para não dizer FP e arquiteturas orientadas a serviços são bestas e não devem considerar hardware. Mas eles priorizam a capacidade de mudar constantemente, manter, ter tamanhos de dados variáveis e outros aspectos. Nos videogames e na IA da máquina, você controla os sinais e dados com muita precisão.
Nota 2 : Os modelos de domínio não possuem comportamento polimórfico nem dependências externas. Eles são "isolados". Isso não significa que eles tenham que ser 100% anêmicos. Eles podem ter muita lógica relacionada à sua construção e alteração de propriedade mutável, se aplicável. Veja DDD "Objetos de Valor" e Entidades de Eric Evans e Mark Seemann.
Nota 3 : Linq e Lambda são muito comuns. Mas quando um usuário cria uma nova função, ele raramente usa Func ou Callable como parâmetros, enquanto no FP seria estranho ver um aplicativo sem funções seguindo esse padrão.
Nota 4 : Não confunda Polimorfismo com Herança. Um CatModel pode herdar o AnimalBase para determinar quais propriedades um animal normalmente possui. Mas, como mostro, modelos como este são um cheiro de código . Se você vir esse padrão, considere dividi-lo e transformá-lo em dados.
Nota 5 : Funções puras podem (e fazem) aceitar funções como parâmetros. A função de entrada pode ser impura, mas pode ser pura. Para fins de teste, sempre seria puro. Mas na produção, embora seja tratado como puro, pode conter efeitos colaterais. Isso não muda o fato de que a função pura é pura. Embora a função de parâmetro possa ser impura. Não é confuso! : D