На самом деле, ОО-код гораздо менее пригоден для повторного использования, и это дизайн. Идея ООП заключается в том, чтобы ограничить операции над отдельными частями данных определенным привилегированным кодом, который находится либо в классе, либо в соответствующем месте в иерархии наследования. Это ограничивает неблагоприятные последствия изменчивости. Если структура данных изменяется, в коде может быть только столько мест, которые могут быть ответственными.
С неизменяемостью вам все равно, кто может работать с любой данной структурой данных, потому что никто не может изменить вашу копию данных. Это значительно облегчает создание новых функций для работы с существующими структурами данных. Вы просто создаете функции и группируете их в модули, которые кажутся подходящими с точки зрения предметной области. Вам не нужно беспокоиться о том, где вписать их в иерархию наследования.
Другой вид повторного использования кода - создание новых структур данных для работы с существующими функциями. Это обрабатывается на функциональных языках с использованием таких функций, как обобщенные типы и классы типов. Например, класс типов 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 сложнее классифицировать, но классификация гораздо менее важна.