Разве передача параметров, которые должны быть Известны, Неявно не Нарушает Инкапсуляцию?

StackOverflow https://stackoverflow.com/questions/1667516

Вопрос

Я часто слышу здесь от разработчиков, работающих на основе тестирования, что то, что функция получает большие объемы информации неявно, - это плохо.Я могу видеть, что это было бы плохо с точки зрения тестирования, но разве это иногда не необходимо с точки зрения инкапсуляции?На ум приходит следующий вопрос:

Является ли использование Random и OrderBy хорошим алгоритмом перемешивания?

По сути, кто-то хотел создать функцию на C # для случайного перетасовки массива.Несколько человек сказали ему, что генератор случайных чисел должен быть передан в качестве параметра.Мне это кажется вопиющим нарушением инкапсуляции, даже если это действительно облегчает тестирование.Разве тот факт, что алгоритм перетасовки массива требует вообще любого состояния, отличного от массива, который он перетасовывает, не является деталью реализации, о которой вызывающий объект не должен заботиться?Разве не было бы правильным местом для получения этой информации неявно, возможно, из локального синглтона потока?

Это было полезно?

Решение

Да, это действительно ломает инкапсуляция.Как и в случае с большинством решений по разработке программного обеспечения, это компромисс между двумя противоположными силами.Если вы инкапсулируете RNG, то вы затрудняете его изменение для модульного теста.Если вы сделаете это параметром, то вы облегчите пользователю изменение RNG (и, возможно, сделаете это неправильно).

Мое личное предпочтение - упростить тестирование, затем предоставить реализацию по умолчанию (в данном конкретном случае конструктор по умолчанию, который создает свой собственный RNG) и хорошую документацию для конечного пользователя.Добавление метода с подписью

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)

это создает Random использование текущего системного времени в качестве начального значения позволило бы использовать большинство обычных вариантов использования этого метода.Оригинальный метод

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)

может быть использован для тестирования (пройти в Random объект с известным исходным кодом), а также в тех редких случаях, когда пользователь решает, что ему нужен криптографически защищенный RNG.Однопараметрическая реализация должна вызывать этот метод.

Другие советы

Я не думаю, что это нарушает инкапсуляцию.Единственное состояние в массиве - это сами данные, а "источник случайности" - это, по сути, сервис.Почему массив, естественно, должен иметь связанный источник случайности?Почему это должен быть синглтон?Как насчет различных ситуаций, которые предъявляют разные требования - напримерскорость против криптографически защищенной случайности?Есть причина, почему java.util.Random имеет SecureRandom подкласс :) Возможно, не имеет значения, предсказуемы ли результаты перетасовки при больших усилиях и наблюдении - или, возможно, так оно и есть.Это будет зависеть от контекста, и это информация, о которой алгоритм перемешивания не должен заботиться.

Как только вы начинаете думать об этом как о сервисе, имеет смысл, что он передается как зависимость.

Да, ты мог бы получите это из локального синглтона потока (и действительно, я собираюсь написать в блоге именно об этом в ближайшие несколько дней), но обычно я бы закодировал это так, чтобы вызывающий абонент получает возможность принять это решение.

Одним из преимуществ концепции "случайность как услуга" является то, что она обеспечивает повторяемость - если у вас есть тест, который не удался, вы можете пройти в Random с определенным исходным кодом и знайте, что вы всегда будете получать одни и те же результаты, что упрощает отладку.

Конечно, всегда есть возможность сделать Random необязательно - используйте локальный синглтон потока по умолчанию, если вызывающий не предоставляет свой собственный.

Я не думаю, что это нарушает инкапсуляцию.

Ваш Пример

Я бы сказал, что возможность предоставления ГСЧ является особенностью класса.Очевидно, я бы предоставил метод, который этого не требует, но я вижу случаи, когда может быть полезно иметь возможность дублировать рандомизацию.

Что, если бы функция перетасовки массивов была частью игры, которая использовала ГСЧ для генерации уровней.Если пользователь хотел сохранить уровень и воспроизвести его позже, возможно, было бы эффективнее сохранить начальное значение RNG.

Общий случай

Простым классам, у которых есть одна задача, подобная этой, обычно не нужно беспокоиться о разглашении своей внутренней работы.То, что они инкапсулируют, - это логика задачи, а не элементы, требуемые этой логикой.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top