В чем разница объектно ориентированного и функционального программирования
Что проверяют
Умеете ли вы объяснить разницу через данные и изменение состояния, а не списком «инкапсуляция, наследование, полиморфизм». Для C#-разработчика следом почти наверняка спросят, что из ФП есть в самом C# и где вы это применяете.
Как отвечать
Суть в том, где живёт состояние и как код его меняет:
- ООП: данные и поведение объединены в объекте, он хранит изменяемое состояние и скрывает его за методами. Расширение идёт через интерфейсы и полиморфизм: новый тип добавить легко, новую операцию над всеми типами трудно;
- ФП: данные отделены от функций и неизменяемы, функции чистые: результат зависит только от аргументов, побочных эффектов нет. Поведение собирается композицией и функциями высшего порядка. Новую операцию добавить легко, новый вариант данных трудно.
Эту асимметрию называют expression problem.
Дальше покажите, что C# давно мультипарадигменный:
- делегаты и лямбды:
Func<T, TResult>иAction<T>, поведение передаётся аргументом; - LINQ:
Where,Select,Aggregateэто по сутиfilter,mapиreduceбез изменения исходной коллекции; - неизменяемые данные:
recordс выражениемwith, свойстваinit,readonly struct, пакетSystem.Collections.Immutable; - сопоставление с образцом:
switch-выражения заменяют виртуальные методы там, где набор вариантов закрыт.
Практический вывод: в реальном коде подходы смешивают. Сервисы и границы модулей описывают классами и интерфейсами для DI, а вычисления внутри делают чистыми функциями над неизменяемыми моделями. Такой код проще тестировать и безопаснее параллелить: общее изменяемое состояние не нужно защищать блокировками.
Где спотыкаются
Сводят ФП к «используем лямбды». Лямбда, меняющая внешнюю переменную, остаётся императивным кодом: суть ФП в чистоте и неизменяемости.
Называют наследование главным способом переиспользовать код. Глубокие иерархии хрупкие, и принцип «композиция вместо наследования» давно принят и в самом ООП.
Считают, что record сам по себе гарантирует неизменяемость. Позиционные свойства у record class действительно только init, но у record struct они изменяемые, а List<T> внутри записи можно поменять в любом случае.