2009-11-04 4 views
11

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

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

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

UrlParser.ParseUrl(url); 

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

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

+0

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

+0

, чтобы проверить это сообщение в блоге (в основном речь идет о Java, но по-прежнему актуальна здесь): http://www.yegor256.com/2014/05/05/oop-alternative-to-utility-classes. html – yegor256

ответ

7

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

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

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

+0

Хорошая точка. System.Uri - хороший пример преобразования статического утилитарного метода, подобного этому объекту. –

+0

Это также очень актуально для их конкретного вопроса, учитывая их пример;) –

+0

Очень плохой пример, как System.Uri, как известно, усеяны проблемами, связанными с первоначальным представлением строк и преобразованиями в/из абсолютных относительных путей. Это то, что происходит при каждом дизайне абстракции и разработке API, вы никогда не получите его прямо из коробки, а разработчикам фреймворка MSFT требуется много времени, чтобы понять это и часто вызывает больше осложнений, чем статические методы, которые легки и известны быть функциональным по своей природе. Но это проблема с подходом «рамки» и «макета дизайна» в целом. –

0

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

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

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

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

Это видео How to design a good API and why it matters от Joshua Bloch объясняет несколько концепций, которые необходимо учитывать при разработке API (это будет ваша библиотека). Хотя он признанный архитектор Java, контент распространяется на все языки программирования.

2

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

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

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

2

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

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

+0

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

+0

Впрыск не снимает зависимость. Это просто упрощает управление. – OscarRyz

+0

Единственный способ ** удалить ** зависимость - удалить его. Я не вижу твоей точки. –

1

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

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

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

1

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

0

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

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

В этом случае я думаю, что все в порядке.

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

1

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

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

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

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

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

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

Смежные вопросы