Функциональный C#. Часть 1. Неизменяемые объекты
18К открытий18К показов
Мы начинаем цикл статей, в которых покажем вам, как программировать на языке C# в парадигме функционального программирования. Нами будут рассмотрены темы:
- Функциональный C#: Неизменяемые объекты
- Функциональный C#: Одержимость примитивами
- Функциональный C#: Ненулевые ссылочные типы
- Функциональный C#: Обработка исключений
Почему мы рассматриваем неизменяемые объекты?
Самой большой проблемой корпоративного программного обеспечения является сложность кода. Читабельность — это, пожалуй, один из самых важных аспектов программирования. И вы должны стремиться к тому, чтобы ваш код был лаконичен. Код, написанный без учета этого фактора, очень сложно анализировать и проверять на корректность.
Давайте рассмотрим такой пример:
Будет ли изменен объект запроса к тому моменту, когда мы выполняем второй поиск? Может быть, да. А, может быть, нет. Это зависит от того, найдем ли мы что-нибудь, осуществив первый поиск. А еще и от того, изменятся ли критерии поиска после выполнения метода AdjustSearchCriteria. Проще говоря, мы не можем знать заранее, изменится ли объект запроса во втором поиске.
А теперь рассмотрим следующий код:
Вот здесь сразу все ясно: после того, как мы ничего не нашли во время первого поиска, метод AdjustSearchCriteria создаст новые критерии, которые в свою очередь будут использоваться во втором поиске.
Итак, какие существуют проблемы в работе с подвергающимися изменениям структурами данных?
- Трудно оценивать написанный код, если мы не можем быть уверенными в том, изменятся ли определенные данные или нет.
- Довольно сложно следовать за многочисленными отсылками, если вам потребовалось взглянуть не только на сам метод, но и на функции, которые вызываются в этом методе.
- Если же вы пишете многопоточное приложение, то отслеживание и отладка кода становятся еще сложнее.
Как описать неизменяемые объекты?
Если у вас есть относительно простой класс, то вы всегда должны рассматривать вопрос о том, чтобы сделать его неизменяемым. Это правило коррелирует с понятием Value Objects — они просты и их легко сделать неизменяемыми.
Так как же нам описать неизменяемые объекты? Давайте рассмотрим пример: у нас есть класс ProductPile, представляющий некоторые продукты, которые мы выставили на продажу:
Чтобы сделать поля класса ProductPile неизменяемыми, мы отметим их доступными только для чтения и создадим конструктор:
Итак, чего же мы добились такой организацией класса?
- Теперь мы можем не волноваться о корректности данных — проверять значение мы будем только один раз в конструкторе.
- Мы абсолютно уверены в том, что значения объектов корректны всегда.
- Объекты автоматически становятся потокобезопасными.
- Увеличилась читаемость кода, поскольку теперь нет необходимости проверять, не изменились ли значения объектов.
Ограничения в использовании
Конечно, все имеет свою цену. Мы можем применить нашу идею в маленьких и простых классах, однако она совсем не применима к большим.
Прежде всего стоит отметить производительность. Если ваш объект получается достаточно большим, то создание его копий каждый раз при изменении какого-то параметра не лучшим образом скажется на быстродействии приложения.
Хорошим примером здесь являются неизменяемые коллекции (immutable collections). Их авторы учли проблемы с производительностью и добавили класс Builder, который позволяет “мутрировать”, изменять коллекцию:
Также вы встретите множество проблем, если попытаетесь сделать изменчивый по своей природе класс неизменяемым. Но пусть вас это не останавливает.
Вывод
Рассмотрите все достоинства и недостатки перевода объектов класса к неизменяемым, оцените затраты и не забывайте рассуждать трезво. В большинстве случаев вы получите выгоду (разумеется, в том случае, когда ваш класс достаточно маленький и простой).
Перевод статьи «Functional C#: Immutability»
18К открытий18К показов