Отдельный класс против метода

Быстрый вопрос по дизайну.

ClassA имеет метод под названием DoSomething (args)

В DoSomething (), прежде чем он сможет что-то сделать, ему необходимо проделать некоторую подготовительную работу с аргументами. Я считаю, что это должно быть инкапсулировано в ClassA (в отличие от выполнения подготовительной работы снаружи и передачи ее внутрь), поскольку больше ничего не должно знать, что эта подготовительная работа требуется для DoSomething.

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

Подготовительная работа в моем конкретном примере заключается в создании списка элементов, удовлетворяющих определенному условию, из args.

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

С точки зрения TDD, я считаю, что это правильный выбор. Затем мы можем провести модульное тестирование ListOfStuff, пока наше сердце не будет удовлетворено. Если бы мы поместили подготовительную работу в частный метод ClassA, мы смогли бы протестировать ее только косвенно, путем тестирования DoSomething ().

Но разве это излишество? С тех пор, как я принял подход TDD и DI, я увидел, что количество классов, которые я пишу, увеличилось - стоит ли мне беспокоиться?

Та.

Для модульного тестирования используйте атрибут InternalsVisibleTo. Это очень полезный атрибут. Это позволяет «дружественной» сборке видеть внутренние методы / свойства / элементы другой сборки.

Simon Hughes 20.12.2008 03:08

Пример: using System; using System.Runtime.CompilerServices; [сборка: InternalsVisibleTo ("ByBox.BusinessLogic.UnitTests" ‌)] пространство имен ByBox.BusinessLogic {....

Simon Hughes 20.12.2008 03:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
2
497
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Какая самая простая вещь, которая могла бы сработать? Это мантра TDD. Не пытайтесь заглядывать слишком далеко вперед. Если придет время создать вспомогательный класс, вы это узнаете, потому что вы будете выполнять все виды связанной работы с помощью нескольких методов в других классах. А пока продолжайте работу по своему методу. Если это делает метод слишком длинным или громоздким для чтения, извлеките работу в отдельный метод. Этот метод также можно проверить, сколько душе угодно, без необходимости в другом классе.

Я думал, вы тестировали только общедоступные методы? Частные методы модульного тестирования, даже с помощью взлома, открытого фреймворком модульного тестирования, всегда казались мне немного «ненадежными».

Duncan 20.12.2008 03:00

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

plinth 20.12.2008 03:04

@Duncan - для модульного тестирования используйте атрибут InternalsVisibleTo. Это очень полезный атрибут. Это позволяет «дружественной» сборке видеть внутренние методы / свойства / элементы другой сборки.

Simon Hughes 20.12.2008 03:07

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

tvanfosson 20.12.2008 03:07

Хммм, хорошо. Возникает другой вопрос - тестировать ли частные методы или нет - но я уверен, что есть много материала, который я могу наверстать. Мой инстинкт - всегда НЕ тестировать частные методы, поскольку они проверяются косвенно. В противном случае вы потратите нереально много времени на написание тестов.

Duncan 20.12.2008 03:15

Дизайн вашей объектной модели следует рассматривать как таковой, а не в контексте вашей стратегии развития. Если сборка ListOFStuff и переход к DoSomething действительно подходят для объектной модели лучше всего, сделайте это, независимо от вашей стратегии развития.

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

Надеюсь, это поможет!

Я должен сказать, что ListOfStuff будет создан исключительно в качестве помощника для этого, поэтому не будет присутствовать в любом дизайне объектной модели. Хм. Но мне делать нравится за явный интерфейс для тестирования. Хм. Это может быть один из тех случаев, когда «нет правильного или неправильного ответа»!

Duncan 20.12.2008 03:18

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

Поместите его в класс, а затем используйте этот класс в другом месте. В противном случае вам придется писать это снова и снова в будущем.

Чтобы сделать его расширяемым и иметь возможность передавать всевозможные различные алгоритмы, паттерн проектирования, который вы будете использовать, - это паттерн Стратегия. Но это на будущее ...

В целом я согласен, ЕСЛИ код также используется где-то еще. Здесь не было такого случая. Здесь он используется только в этом одном методе. Создавая новый метод, я это вижу, но создание нового класса на этом этапе было бы излишним.

tvanfosson 20.12.2008 03:09

@tvanfosson - Вы правы, код на данный момент больше нигде не будет использоваться. Я знаком с мантрой «рефакторинг, если используется более одного раза», но в наши дни я также вижу дизайн в гораздо большей степени, чем разделение проблем. Но я «обеспокоен» (!), Я захожу слишком далеко!

Duncan 20.12.2008 03:12

@Duncan, но единственный метод, связанный с расчетом, - это текущий. Вам нужно сбалансировать принципы - в этом случае SoC необходимо сбалансировать с YAGNI (вам это не понадобится).

tvanfosson 20.12.2008 03:33
Ответ принят как подходящий

Здесь есть несколько эвристик.

  1. Есть ли в этом классе положение, что выживает от призыва к призыв? Получится ли эта подготовительная работа делается каждый раз, когда вам нужно doSomething (), или это уже сделано и спасен? Если так, то это свидетельствует о том, что класс.
  2. Должно ли произойти это вычисление в более чем одном месте? Если так, это аргумент в пользу класса.
  3. Могут ли детали реализация doSomething () метод, или подготовительные работы для это, изменить, не затрагивая включающий класс? Если так, то это утверждает для класса.

Ну, три эвристики. Никто не ждет испанской инквизиции.

Определенно нет для 1 и 2, большой возможно для 3. Мне действительно нравится, как он инкапсулирует всю эту подготовительную работу в аккуратный класс, но я думаю, что, возможно, я считаю разделение проблем слишком экстремальным. Это была мысль в пятницу днем!

Duncan 20.12.2008 03:23

Нет, мне кажется, ты правильно думаешь. У вас может быть аргумент в пользу частного внутреннего класса; в противном случае поместите подготовительную работу в частный метод.

Charlie Martin 20.12.2008 21:54

Since adopting the TDD and DI approach, I've seen the number of classes that I write multiply - should I be worried?

Если ваша цель - процедурное программирование, да. Но поскольку вы почти наверняка хотите работать в объектно-ориентированной манере, нет.

Большинство людей используют слишком мало типов, тратят слишком мало времени на размышления об объектно-ориентированном дизайне.

Ваши вопросы о классовой ответственности отражают зрелость мышления (имхо).

SoC действителен только в том случае, если рассматриваемая «проблема» не имеет ничего общего с классом, или вы обнаружите, что классы разделяют эту «проблему» (иначе говоря, нарушая DRY). В вашем случае кажется, что код является внутренним для класса, поэтому, возможно, функция private была бы более подходящей.

Как сказал тванфоссон выше, вам нужно сбалансировать SoC с YAGNI. Лично я думаю, что вы, возможно, обдумываете это преждевременно (я знаю! Я тоже постоянно так делаю).

Да, я думаю, если бы вы выполняли SoC как чисто академическое упражнение, или ListOfStuff делал что-то ДЕЙСТВИТЕЛЬНО сложное, и я хотел бы протестировать это самостоятельно, у меня был бы класс ListOfStuff, который бы выполнял эту работу. Однако с прагматической точки зрения я бы просто поместил всю работу в ClassA. Компромисс!

Duncan 14.01.2009 17:11

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