Na verdade, o código OO é muito menos reutilizável, e isso é por design. A idéia por trás do OOP é restringir as operações em partes específicas de dados a determinado código privilegiado que está na classe ou no local apropriado na hierarquia de herança. Isso limita os efeitos adversos da mutabilidade. Se uma estrutura de dados mudar, há apenas muitos lugares no código que podem ser responsáveis.
Com a imutabilidade, você não se importa com quem pode operar em qualquer estrutura de dados, porque ninguém pode alterar sua cópia dos dados. Isso facilita muito a criação de novas funções para trabalhar nas estruturas de dados existentes. Você acabou de criar as funções e agrupá-las em módulos que parecem apropriados do ponto de vista do domínio. Você não precisa se preocupar sobre onde encaixá-los na hierarquia de herança.
O outro tipo de reutilização de código é a criação de novas estruturas de dados para trabalhar nas funções existentes. Isso é tratado em linguagens funcionais usando recursos como genéricos e classes de tipo. Por exemplo, a classe de tipo Ord de Haskell permite que você use a sort
função em qualquer tipo com uma Ord
instância. É fácil criar instâncias se elas ainda não existirem.
Tome seu Animal
exemplo e considere implementar um recurso de alimentação. A implementação direta do OOP é manter uma coleção de Animal
objetos e percorrer todos eles, chamando o feed
método em cada um deles.
No entanto, as coisas ficam complicadas quando você detalha os detalhes. Um Animal
objeto sabe naturalmente que tipo de alimento ele come e quanto precisa para se sentir satisfeito. Ele não naturalmente sabe onde o alimento é mantido e quanto está disponível, portanto, um FoodStore
objeto acaba de se tornar uma dependência de cada Animal
, seja como um campo do Animal
objeto, ou passado como um parâmetro do feed
método. Como alternativa, para manter a Animal
classe mais coesa, você pode ir feed(animal)
para o FoodStore
objeto ou criar uma abominação para uma classe chamada de AnimalFeeder
algo ou algo assim.
No FP, não há inclinação para os campos de um Animal
permanecerem sempre agrupados, o que tem algumas implicações interessantes para a reutilização. Digamos que você tenha uma lista de Animal
registros, com campos como name
, species
, location
, food type
, food amount
, etc. Você também tem uma lista deFoodStore
registros com campos como location
, food type
, e food amount
.
O primeiro passo na alimentação pode ser mapear cada uma dessas listas de registros para listas de (food amount, food type)
pares, com números negativos para as quantidades dos animais. Você pode criar funções para fazer todo tipo de coisa com esses pares, como somar as quantidades de cada tipo de alimento. Essas funções não pertencem perfeitamente a um Animal
ou a um FoodStore
módulo, mas são altamente reutilizáveis por ambos.
Você acaba com várias funções que fazem coisas úteis, [(Num A, Eq B)]
reutilizáveis e modulares, mas você tem problemas para descobrir onde colocá-las ou como chamá-las como um grupo. O efeito é que os módulos FP são mais difíceis de classificar, mas a classificação é muito menos importante.