На самом деле, ОО-код гораздо менее пригоден для повторного использования, и это дизайн. Идея ООП заключается в том, чтобы ограничить операции над отдельными частями данных определенным привилегированным кодом, который находится либо в классе, либо в соответствующем месте в иерархии наследования. Это ограничивает неблагоприятные последствия изменчивости. Если структура данных изменяется, в коде может быть только столько мест, которые могут быть ответственными.
С неизменяемостью вам все равно, кто может работать с любой данной структурой данных, потому что никто не может изменить вашу копию данных. Это значительно облегчает создание новых функций для работы с существующими структурами данных. Вы просто создаете функции и группируете их в модули, которые кажутся подходящими с точки зрения предметной области. Вам не нужно беспокоиться о том, где вписать их в иерархию наследования.
Другой вид повторного использования кода - создание новых структур данных для работы с существующими функциями. Это обрабатывается на функциональных языках с использованием таких функций, как обобщенные типы и классы типов. Например, класс типов Ord в Haskell позволяет использовать sortфункцию для любого типа с Ordэкземпляром. Экземпляры легко создавать, если они еще не существуют.
Возьмите свой Animalпример и подумайте о реализации функции кормления. Простая реализация ООП состоит в том, чтобы поддерживать коллекцию Animalобъектов и перебирать все их, вызывая feedметод для каждого из них.
Однако, когда дело доходит до деталей, все становится сложнее. AnimalОбъект естественно знает , какую пищу он ест, и сколько это необходимо для того , чтобы чувствовать себя полностью. Естественно, он не знает, где хранится еда и сколько ее имеется, поэтому FoodStoreобъект только что стал зависимым от каждого Animal, либо как поле Animalобъекта, либо передан в качестве параметра feedметода. С другой стороны, чтобы сохранить Animalкласс более сплоченным, вы можете перейти feed(animal)к FoodStoreобъекту, или вы можете создать мерзость класса, называемого AnimalFeederили что-то подобное.
В FP нет склонности к тому, чтобы поля Animalвсегда оставались сгруппированными, что имеет некоторые интересные последствия для повторного использования. Скажем , у вас есть список Animalзаписей, с такими областями , как name, species, location, food type, food amountи т.д. У вас также есть список FoodStoreзаписей с полями , как location, food typeи food amount.
Первым шагом в кормлении может быть сопоставление каждого из этих списков записей со списками (food amount, food type)пар с отрицательными числами для количества животных. Затем вы можете создавать функции для выполнения всех этих действий с этими парами, например, суммировать количество продуктов каждого типа. Эти функции не принадлежат ни к одному, Animalни к FoodStoreмодулю, но их можно использовать многократно.
В итоге вы получаете кучу функций, которые делают полезные вещи, [(Num A, Eq B)]которые можно использовать многократно и модульно, но у вас не получается понять, где их разместить или как их называть группой. В результате модули FP сложнее классифицировать, но классификация гораздо менее важна.