Этот вопрос субъективен, но мне было просто любопытно, как к этому подходит большинство программистов. Пример ниже приведен на псевдо-C #, но это также должно относиться к Java, C ++ и другим языкам ООП.
В любом случае, когда я пишу вспомогательные методы в моих классах, я склонен объявлять их как статические и просто передавать поля, если они нужны вспомогательному методу. Например, учитывая приведенный ниже код, я предпочитаю использовать вызов метода № 2 .
class Foo
{
Bar _bar;
public void DoSomethingWithBar()
{
// Method Call #1.
DoSomethingWithBarImpl();
// Method Call #2.
DoSomethingWithBarImpl(_bar);
}
private void DoSomethingWithBarImpl()
{
_bar.DoSomething();
}
private static void DoSomethingWithBarImpl(Bar bar)
{
bar.DoSomething();
}
}
Моя причина для этого заключается в том, что он проясняет (по крайней мере, на мой взгляд), что вспомогательный метод имеет возможный побочный эффект для других объектов - даже без чтения его реализации. Я обнаружил, что могу быстро использовать методы, которые используют эту практику и, таким образом, помогают мне в отладке вещей.
Что вы предпочитаете делать в своем собственном коде и каковы ваши причины для этого?
Ответы:
Это действительно зависит. Если значения, с которыми работают ваши помощники, являются примитивами, то статические методы - хороший выбор, как отметил Петер.
Если они являются сложными, то SOLID применяется, более конкретно, S , в I и D .
Пример:
Это будет о вашей проблеме. Вы можете сделать
makeEveryBodyAsHappyAsPossible
статический метод, который будет принимать необходимые параметры. Другой вариант:Теперь
OurHouse
не нужно знать о тонкостях правил распространения файлов cookie. Это должен только сейчас объект, который реализует правило. Реализация абстрагируется от объекта, единственной обязанностью которого является применение правила. Этот объект может быть проверен в изоляции.OurHouse
может быть проверено с помощью простого макетаCookieDistributor
. И вы можете легко решить изменить правила распространения файлов cookie.Однако позаботьтесь, чтобы вы не переусердствовали. Например, наличие сложной системы из 30 классов действует как реализация
CookieDistributor
, где каждый класс просто выполняет крошечную задачу, на самом деле не имеет смысла. Моя интерпретация SRP заключается в том, что он не только диктует, что каждый класс может иметь только одну ответственность, но также и то, что один класс должен нести одну ответственность.В случае примитивов или объектов, которые вы используете как примитивы (например, объекты, представляющие точки в пространстве, матрицы или что-то еще), статические вспомогательные классы имеют большой смысл. Если у вас есть выбор, и он действительно имеет смысл, тогда вы можете подумать о добавлении метода в класс, представляющий данные, например, целесообразно
Point
иметьadd
метод. Опять же, не переусердствуйте.Таким образом, в зависимости от вашей проблемы, есть разные способы решения этой проблемы.
источник
Это известная идиома, объявляющая методы служебных классов
static
, поэтому такие классы никогда не нужно создавать. Следование этой идиоме облегчает понимание вашего кода, и это хорошо.Однако у этого подхода есть серьезное ограничение: такие методы / классы не могут быть легко смоделированы (хотя AFAIK, по крайней мере, для C #, есть платформы для имитации, которые могут достичь даже этого, но они не являются обычным явлением, и, по крайней мере, некоторые из них коммерческий). Поэтому, если у вспомогательного метода есть какая-либо внешняя зависимость (например, БД), которая делает его - то есть его вызывающих - сложным для модульного тестирования, лучше объявить его нестатичным . Это позволяет вводить зависимости, тем самым упрощая вызовы метода для модульного тестирования.
Обновить
Пояснение: выше говорится о служебных классах, которые содержат только вспомогательные методы низкого уровня и (как правило) без состояния. Вспомогательные методы внутри не зависящих от состояния классов являются другой проблемой; извинения за неправильное толкование ФП.
В этом случае я чувствую запах кода: метод класса A, который работает в основном с экземпляром класса B, может на самом деле иметь лучшее место в классе B. Но если я решу оставить его там, где он есть, я предпочитаю вариант 1, как это проще и легче читать.
источник
Я предпочитаю # 1 (
this->DoSomethingWithBarImpl();
), если, конечно, вспомогательный метод не нуждается в доступе к данным / реализации экземпляраstatic t_image OpenDefaultImage()
.Публичный интерфейс и частная реализация и члены являются отдельными. программы было бы гораздо труднее читать, если бы я выбрал № 2. с # 1 у меня всегда есть члены и экземпляр доступны. по сравнению со многими реализациями на основе ОО, я склонен использовать много инкапсуляции и очень мало членов на класс. Что касается побочных эффектов - я согласен с этим, часто существует проверка состояния, которая расширяет зависимости (например, аргументы, которые нужно будет передать).
# 1 намного проще читать, поддерживать и имеет хорошие характеристики производительности. Конечно, будут случаи, когда вы можете поделиться реализацией:
Если бы # 2 было хорошим распространенным решением (например, по умолчанию) в кодовой базе, я был бы обеспокоен структурой проекта: классы делают слишком много? недостаточно ли инкапсуляции или недостаточно повторного использования? уровень абстракции достаточно высок?
наконец, # 2 кажется излишним, если вы используете ОО-языки, где поддерживается мутация (например,
const
метод).источник