Страницы

Поиск по вопросам

четверг, 5 декабря 2019 г.

Публичные вложенные классы - плохая практика?

#c_sharp #net


Вот смотрю я на некоторые классы стандартных библиотек и думаю, а почему их не сделали
вложенными и публичными, чтобы подчеркнуть их "ареал".

Например, есть DataTable и DataRow. DataRow нигде, вроде, не используется вне контекста
DataTable и более того, отсутствует конструктор => создание возможно только через фабричный
метод. Или DataColumn...

Так почему бы не подчеркнуть принадлежность вынеся классы во внутрь DataTable?

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

Почему так?
    


Ответы

Ответ 1



Ну почему же, используется, но только для тех типов, которые не особо фигурируют напрямую в коде. Например, List.Enumerator, который используется только неявно кодом, генерируемым компилятором для foreach. Для обычных типов их использовать действительно не рекомендуется, на это даже есть специальное предупреждение анализаторов CA1034. Причина банальна - это неудобно; при каждом использовании такого типа снаружи нужно приписывать имя содержащего типа, сократить используя using нельзя. Ну и с точки зрения архитектуры: вложенность это не просто область видимости, она позволяет вложенному классу работать с private-членами содержащего. Если это не нужно по логике взаимодействия этих классов, лучше не связываться с таким нарушением инкапсуляции.

Ответ 2



Класс в классе увеличивает размер файла. Если в файле более трёхсот строк, с ним уже не очень удобно работать. Если ваш класс становится слишком большим, это подсказывает, что, возможно, нарушен принцип единственной ответственности (single responsibility). Поэтому классы в классах используют только тогда, когда вы передаёте важную информацию для программиста, который будет поддерживать и изменять ваш код. Если класс Bar находится в Foo, значит, он должен знать, как устроен Foo. Пример: реализуем паттерн Memento: Клиент является "посыльным" за Memento, но только исходный объект может сохранять и извлекать информацию из Memento (Memento является "непрозрачным" для клиентов и других объектов). Из описания паттерна мы понимаем, что класс Originator и класс Memento должны знать друг о друге гораздо больше, чем остальные классы. Именно для подчёркивания этого факта нужно разместить один внутри другого. Я бы размещал Memento внутри Originator и вынес бы в него сохранение и восстановление состояния, чтобы оставить в Originator только его основную ответственность. Поскольку в подавляющем большинстве случаев мы всё-таки хотим скрыть детали реализации, мы не используем этот приём слишком часто.

Комментариев нет:

Отправить комментарий