Функциональное Программирование в C#. Начало
Паттерны функционального программирования могут показаться академичными и абстрактными. Такие термины, как «монады» и «функторы», отпугивают многих разработчиков. Но за пугающей терминологией скрываются практические паттерны, которые могут сделать код более безопасным и удобным для поддержки.
В последнее время в C# добавили множество функций из функционального программирования:
- Записи для неизменяемости,
- LINQ для функциональных преобразований,
- Лямбда-выражения для функций первого класса.
Эти функции — не просто синтаксический сахар — они помогают предотвращать ошибки и упрощают понимание кода.
В этой серии рассмотрим практические паттерны, которые можно использовать в проектах на C#.
1. Функции высшего порядка
Функции высшего порядка могут принимать другие функции в качестве параметров или возвращать их в качестве результатов. Они позволяют писать более гибкий и компонуемый код, поскольку вы можете передавать поведение как данные. Типичные примеры — Where и Select из LINQ, которые принимают функции для преобразования данных. Рассмотрим пример валидации:
public class OrderValidator
{
public bool ValidateOrder(Order order)
{
if (order.Items.Count == 0) return false;
if (order.TotalAmount <= 0) return false;
if (order.ShippingAddress == null) return false;
return true;
}
}
Что, если нам нужны:
- разные правила проверки для разных стран.
- повторное использование некоторых проверок,
- по-разному комбинировать проверки.
Вот как функции высшего порядка делают это более гибким:
public static class OrderValidation
{
public static Func<Order, bool>
Create(string country,
decimal minOrder)
{
var baseValidations = CombineValidations(
o => o.Items.Count > 0,
o => o.TotalAmount >= minOrder,
o => o.ShippingAddress != null
);
return country switch
{
"US" => CombineValidations(
baseValidations,
o => IsValidUSAddress(o.ShipAddress)),
"EU" => CombineValidations(
baseValidations,
o => IsValidVATNumber(o.VatNumber)),
_ => baseValidations
};
}
private static Func<Order, bool>
CombineValidations(
params Func<Order, bool>[] validations) =>
order => validations.All(v => v(order));
}
// Использование
var usValidator =
OrderValidation.Create("US", 25.0m);
var euValidator =
OrderValidation.Create("EU", 30.0m);
Подход с использованием функций высшего порядка делает валидаторы комбинируемыми, тестируемыми и легко расширяемыми. Каждое правило валидации — это простая функция, и мы можем комбинировать их.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/functional-programming-in-csharp-the-practical-parts