Должен ли я подкласс List <T> или иметь его как свойство?
Я столкнулся с этой проблемой довольно часто в течение последних нескольких месяцев, в течение которых я строил эту систему. Сценарий таков: у меня есть такой объект, который по существу является списком других объектов, но имеет некоторые другие свойства, специфичные по своей природе. Например:
- Класс
Tests
:
- Содержит много объектов
Test
- Имеет свойства:
-
DefaultTimeouts
-
DefaultNumberOfTries
Должен ли я иметь этот подкласс класса List<Test>
или должен ли я наследовать его от Object
, просто имея список как свойство рядом с другими полями?
Я знаю, что это может быть немного субъективным, и личный вкус может сыграть здесь определенную роль, но я искренне хотел бы узнать ваше мнение об этом.
Ответы
Ответ 1
В отличие от большинства ответов здесь я бы не стал подклассом из List в большинстве случаев. Я обнаружил, что наследование класса для повторного использования функций обычно вызывает проблемы позже.
Обычно у меня есть свойство типа List (или IList), которое возвращает ссылку на список. Обычно вам нужно только получить свойство здесь. Вы можете контролировать доступ к списку, выбирая для возврата версии только для чтения с помощью .AsReadOnly() или просто отображая список как IEnumerable.
В тех случаях, когда я хочу, чтобы тесты были списком, я обычно реализую IList и вызываю внутреннее поле List для фактических реализаций IList. Это немного больше работы и приводит к некоторому еще коду для поддержки, но я обнаружил, что это лучше обслуживается, чем наследование List только для его реализации.
Ответ 2
Подкласс из списка <T> . Если у вас есть Generic как свойство, он не так инкапсулирован как подкласс.
Если это выглядит как List <T> , и это похоже на List <T> , это, вероятно, List <T> .
Я бы назвал это TestCollection.
Ответ 3
Если это буквально делает все, что делает a List
, и все функции List
будут действовать на объект Tests
интуитивно понятным способом, который дает правильный результат, тогда, на мой взгляд, он должен просто подклассом List<Test>
.
В противном случае у вас будет класс с тонны методов, которые просто вызовут метод с тем же именем в переменной List<Test>
в экземпляре. Это будет просто несовершенное расширение самого класса List<Test>
.
Ответ 4
Наследование обычно сопоставляется с отношением "is-a". Поскольку ваш контейнер представляет собой список, но с некоторыми другими вещами, я бы наследовал от List и добавлял ваши дополнительные свойства в ваш подкласс.
Ответ 5
Я не думаю, что у вас есть простой "список тестов", потому что вам нужно что-то еще. Я предлагаю вам назвать его TestSuite
и сделать Список как свойство. Имеет-а намного легче поддерживать по сравнению с наследованием.
В общем, я был бы очень осторожен, чтобы наследовать что-то вроде List
.
Ответ 6
При чтении ответов кажется, что ключевой вопрос заключается в том, какой длиной является ваш объект действительно список? Поэтому, возможно, хорошим компромиссом между опасностями наследования и отсутствием прозрачности композиции было бы иметь List<Test>
как частный бэкэнд и выставлять только те методы, которые будут использоваться.
Ответ 7
В вашем примере вы сказали: "Тест классов содержит множество объектов теста", а не "Тест классов" - это набор объектов "Тесты". IMO нет необходимости подкласса List в этом сценарии, если вам не нужен интерфейс List-like для этого класса.
Однако ответ действительно зависит от контекста класса Tests. Если он ведет себя как List и будет использоваться в контекстах, где ожидается список объектов, наследуйте от List.
Обратите внимание, что наследование сложнее, чем состав.
Кроме того, я бы переименовал тесты в TestCollection (если вы являетесь списком подкласса) или что-то вроде TestUnit (если он будет содержать список тестовых классов.
Ответ 8
"Предпочтительная композиция над наследованием" всегда является хорошим правилом. Являются ли методы, которые используют этот класс, используя все методы List, а также те, которые вы добавляете, или только те, которые вы добавляете?