День 1097. #BestPractices
Лучшие Практики Разработки в C#. Начало
Написанию кода можно научиться из онлайн документации или учебника. Однако навыки анализа и проектирования так просто не получить. В этой серии постов рассмотрим некоторые передовые методы проектирования, которые на практике доказали свою эффективность.
1. Унифицированный возвращаемый объект
Иногда нужно как-то описать данные, возвращаемые методом. Мы называем это метаданными, так как это не собственно данные, а некоторая важная информация, которая может быть использована позже.
Иногда понятно, что метод возвращает какие-то данные, например коллекцию объектов, и некоторые метаданные (общее количество объектов и текущую страницу). Но иногда наличие метаданных не очевидно. Например, метод void RenameFile(string newName) принимает новое имя файла и ничего не возвращает. В реальном мире это может быть проблемой, потому что операция может завершиться неудачей, и тогда метод должен что-то вернуть, чтобы сообщить об этом вызывающей стороне.
Я уже слышу ваши варианты: вернуть булевый результат, вернуть новое имя файла в случае успеха или пробросить исключение вызывающему коду. Эти решения могут работать, однако лучше всего здесь вернуть унифицированный объект с некоторыми данными, описывающими, что на самом деле произошло:
public enum FileRenameFailureReason {
None = 0,
ExistingName = 1,
PathTooLong = 2
}
public class FileRenameResult
{
public FileRenameFailureReason FailureReason { get; }
public string FinalName { get; }
public bool Succeeded =>
FailureReason == FileRenameFailureReason.None;
}
Некоторые преимущества возврата унифицированного объекта:
- Перемещение логики туда, где она используется: обработчик хранит логику возврата правильного результата, вызывающий код – логику обработки этого результата (например, выдачи сообщения пользователю).
- Определение более чёткого контракта между вызывающим кодом и обработчиком.
- Теперь вызывающий код может принимать точные решения на основе полной информации, предоставленной обработчиком.
- Работа с унифицированными объектами значительно упрощает разработку общих модулей.
2. Разбиение на страницы
Разбиение на страницы — один из широко используемых паттернов, но почти никто не говорит о нём с точки зрения практики проектирования. Когда вы создаёте API, вы должны контролировать объём данных, проходящих через него. Поэтому при разработке API полезно спроектировать стратегию регулирования объема трафика. Вы можете сказать, что у вас нет лимитов, но скорее всего они просто настолько большие, что вы их не осознаёте. Например, если у вас есть метод GetAllEmployees, вы можете разрешить вызывающей стороне получать данные всех сотрудников. А что, если когда-нибудь в системе будет 10 000 сотрудников. Сейчас самое подходящее время вернуть только первые 1000 или 5000 и предоставить вызывающей стороне объект метаданных, сообщающий, что произошло и как получить следующую порцию.
3. Делегаты вместо Func<>
Когда нужно определить ссылку на метод, иногда полезнее явно определить делегат, а затем его использовать:
public delegate bool MessageHandler(int id, string msg);
public class Module1
{
public MessageHandler Handler { get; set; }
}
public class Module2
{
public Func<int, string, bool> Handler { get; set; }
}
Отличие в том, что вы получите более информативные подсказки в IntelliSense в виде имён параметров вместо arg1, arg2 в случае использования Func<>.
Продолжение следует…
Источник: levelup.gitconnected.com/design-…b7c3500a