Полезные классы.. Хорошо или плохо?

Я читал, что создание зависимостей с использованием статических классов/синглетонов в коде, является плохой формой и создает проблемы, т.е. плотное соединение и модульное тестирование.

У меня есть ситуация, когда у меня есть группа методов разбора URL-адресов, которые не имеют состояния, связанного с ними, и выполняют операции, используя только входные аргументы метода. Я уверен, что вы знакомы с таким методом.

В прошлом я бы начал создавать класс и добавлять эти методы и вызывать их непосредственно из моего кода, например.

UrlParser.ParseUrl(url);

Но подождите минуту, представляя зависимость другого класса. Я не уверен, являются ли эти классы "полезности" плохими, поскольку они без гражданства, и это сводит к минимуму некоторые проблемы с указанными статическими классами и синглонами. Может ли кто-нибудь прояснить это?

Должен ли я перемещать методы в вызывающий класс, то есть если только метод вызова будет использовать метод. Это может нарушить "Единый принцип ответственности".

Ответ 1

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

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

Например, в вашем случае я считаю, что UrlParser.ParseUrl(...), вероятно, лучше обрабатывается как класс. Посмотрите System.Uri в BCL - это обрабатывает чистый, простой в использовании интерфейс для Uniform Resource Indentifiers, который работает хорошо и поддерживает фактическое состояние. Я предпочитаю этот подход к утилитарному методу, который работает с строками и заставляет пользователя передавать строку, не забудьте проверить ее и т.д.

Ответ 2

Полезные классы в порядке..... если они не нарушают принципы проектирования. Используйте их так же успешно, как и для основных классов фреймворка.

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

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

Ответ 3

Вы всегда можете создать интерфейс и использовать его с инъекцией зависимостей с экземплярами классов, которые реализуют этот интерфейс вместо статических классов.

Вопрос становится, действительно ли стоит усилий? В некоторых системах ответ в да, но в других, особенно в меньших, ответ, вероятно, нет.

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

Это действительно зависит от контекста и от того, как мы его используем.

Утилиты, сами по себе, неплохие. Однако, это будет плохо, если мы будем использовать его плохо. Каждый шаблон дизайна (особенно шаблон Singleton) можно легко превратить в анти-шаблон, то же самое касается классов Utility.

В разработке программного обеспечения нам нужна балансировка между гибкостью и простотой. Если мы собираемся создать StringUtils, который отвечает только за манипуляции с строкой:

  • Нарушает ли он SRP (принцип единой ответственности)? → Нет, это разработчики, которые ставят слишком много обязанностей в классы утилиты, которые нарушают SRP.
  • "Он не может быть введен с использованием каркасов DI" → Будет ли изменена реализация StringUtils? Мы собираемся переключить его реализации во время выполнения? Мы будем издеваться над этим? Конечно нет.

= > Классы полезности, themselve, неплохие. Это ошибка разработчиков, которые делают это плохо.

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

Ответ 7

Они прекрасны, пока вы хорошо их разрабатываете (т.е. вам не нужно время от времени менять свою подпись).

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

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

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

Это видео Как создать хороший API и почему это важно Джошуа Блоха, объясняет несколько концепций, которые нужно учитывать при разработке API (это будет ваша библиотека утилиты). Хотя он признанный архитектор Java, контент распространяется на все языки программирования.

Ответ 8

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

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

В этом случае я думаю, что это нормально.

FYI существует класс system.web.httputility, который содержит много общих утилит http, которые могут вам пригодиться.