Что такое «лучшая практика» здесь?
Лучшая практика заключается в применении подхода holisti c с особым акцентом на потребностях абонента . Это не обязательно означает предоставление максимальной гибкости для абонента! Это означает понимание вариантов использования для вызывающего абонента.
Способ, которым я лично разработал бы это решение:
// Notice: User, not Users. This notifies a single user.
void NotifyUser(int id)
{
// notify the user
}
void NotifyUsers(IEnumerable<int> ids)
{
foreach(var id in ids)
NotifyUser(id);
}
Это подчеркивает для вызывающего абонента, что, если вы хотите сделать это один раз, вы используйте NotifyUser
, и если у вас есть любая последовательность пользователей - не просто список - тогда вы вызываете NotifyUsers
с этой последовательностью.
Теперь следующий вопрос, который я бы задал есть: хотят ли звонящие когда-либо делать это:
NotifyUsers(10, 20, 30);
В этом случае я бы добавил третью функцию:
void NotifyUsers(params int[] ids)
{
NotifyUsers((IEnumerable<int>) ids);
}
Этот метод является гибким для звонящего, гарантируя, что большинство ваших методов тривиальны. Если в NotifyUser есть ошибка, вы хотите исправить ее только в одном месте.
Недостатком этого подхода является то, что NotifyUsers()
становится легальным и не допускается. Кто-то может назвать это случайно и подумать, что он что-то делает. В этом случае вы можете заставить хотя бы одного:
void NotifyUsers(int id, params int[] ids)
{
NotifyUser(id);
NotifyUsers((IEnumerable<int>) ids);
}
Это иллюстрирует важный момент: размышление о потребностях звонящего также включает в себя психоанализ людей, которых вы не знаете, чтобы выяснить что они собираются делать неправильно, а затем предотвращать это, прежде чем это произойдет . Разработка API-интерфейсов, которые естественным образом приводят людей к только успеху, трудна!
(Также обратите внимание, что в этих набросках отсутствует обработка ошибок; возможно, вы хотите проверить, что последовательности и массивы не равны NULL, и и так далее.)
Ключ здесь: начать с понимания потребностей вызывающего абонента; разработать API, который отвечает их потребностям. Тогда осуществите это. Тем не менее, каким должен быть выбор реализации?
Это зависит от того, как работает уведомление последовательности пользователей. Решение, которое я набросал выше, делает некоторые предположения. Вот они:
- не более эффективно уведомлять сотню пользователей "за один раз", чем уведомление сотен пользователей по одному за раз.
- Если уведомление одного пользователя в последовательности завершается неудачно, правильное решение - перестать уведомлять.
Что если эти предположения неверны? Рассмотрим API, который обновляет базу данных, и дорогой частью является не обновление, а установление соединения с базой данных. В этом случае вы НЕ хотите писать:
void NotifyUser(int id)
{
Connect(); // Expensive
Update(id);
Disconnect();
}
void NotifyUsers(IEnumerable<int> ids)
{
foreach(var id in ids)
NotifyUser(id);
}
Потому что теперь вы делаете 100 подключений для 100 пользователей. Вместо этого вы хотите перевернуть скрипт:
void NotifyUser(int id)
{
NotifyUsers(Enumerable.Repeat(id, 1));
}
void NotifyUsers(IEnumerable<int> ids)
{
Connect();
foreach(var id in ids)
Update(id);
Disconnect();
}
Обратите внимание, что при переписывании реализации я не переписывал API; помните, что мы уже разработали API, чтобы он был хорошим для абонентов , поэтому, если этот API отвечает их потребностям, не меняйте его! Методы: абстракции ; мы можем изменить детали, чтобы соответствовать требованиям производительности. (И если мы не можем достичь поставленных целей из-за проблем с дизайном API, то мы не спроектировали API, который в первую очередь отвечал бы потребностям вызывающего абонента.)
А что теперь с обработкой ошибок? Существует множество возможностей:
- Уведомления требуются для максимальной эффективности. Если одно уведомление в последовательности завершается сбоем, перехватите исключение, сожмите его и продолжайте работу с другими пользователями. Никогда не сообщайте вызывающему абоненту о сбое
- Уведомления должны быть максимально эффективными, но вызывающие абоненты должны знать обо всех сбоях. Зарегистрируйте исключения и либо перебросьте их, либо верните отчет об ошибках вместо void.
- Уведомления должны быть «все или ничего». То есть, если десятое уведомление терпит неудачу, то отменяет предыдущие уведомления, чтобы сохранить мир согласованным Это сложно . Вы не можете отменить звонок.
И так далее. Снова очень внимательно подумайте о потребностях звонящего . Что они ожидают, произойдет в случае неудачи? Вы знаете, как написать логи c, чтобы делать то, что ожидает вызывающий? Можете ли вы четко задокументировать это, чтобы звонящий знал, оправданы ли его ожидания?