IOC - Следует ли использовать классы со статическими вспомогательными методами с IOC?

Просто пытаюсь по-прежнему опираться на принципы МОК.

Q1: Статические методы. Следует ли подключать классы со статическими вспомогательными методами с помощью IOC?

Например, если у меня есть класс HttpUtils с несколькими статическими методами, должен ли я пытаться передать его другим классам бизнес-логики через IOC?

Следуйте этим вопросам:

Q2: Синглтоны. Что касается таких вещей, как ведение журнала, где вы обычно можете получить к нему доступ с помощью вызова типа Logger.getInstance(). Вы обычно оставляете это как есть, и НЕ используете IOC для инъекции регистратора в бизнес-классы, которые в нем нуждаются?

Q3: Статические классы. Я действительно не использовал эту концепцию, но есть ли какие-либо рекомендации относительно того, как вы обычно справляетесь с этим, если вы переходите на подход, основанный на IOC.

Спасибо заранее.

Ответ 1

Самое смешное в IoC заключается в том, что объекты, написанные в стиле, обычно отделены от этих деталей.

В качестве примера можно использовать класс утилиты:

public class HttpUtils
{
    public static void DoStuff(int someValue)
    {
        // ...
    }
}

В приложении, не ориентированном на IoC, вы можете использовать этот метод напрямую:

public class Foo
{
    public int Value { get; set; }

    public void DoStuff()
    {
        HttpUtils.DoStuff(Value);
    }
}

Однако это связывает определение DoStuff непосредственно с его реализацией. IoC стремится развести эти детали, поэтому вместо этого мы определяем операцию самостоятельно:

public interface IDoesStuff
{
    void DoStuff(int someValue);
}

Затем мы оставляем место в Foo для изменения реализации:

public class Foo
{
    private readonly IDoesStuff _doesStuff;

    public Foo(IDoesStuff doesStuff)
    {
        _doesStuff = doesStuff;
    }

    public int Value { get; set; }

    public void DoStuff()
    {
        _doesStuff.DoStuff(Value);
    }
}

Это отделяет Foo от HttpUtils. Разработчик концепции DoStuff теперь представляет собой конфигурационную деталь, а не внутреннюю зависимость (как и со статическим методом).

Обратите внимание, что Foo понятия не имеет, если его IDoesStuff является одиночным или нет. Это время жизни также является деталью конфигурации, а не неотъемлемой деталью Foo.

Подводя итог, IoC и static, как правило, расходятся, поскольку IoC способствует изменению и static, по определению, предотвращает его. Объявите свои зависимости в своих конструкторах, и вы почти никогда не используете функциональность static.

Ответ 2

Контейнер IoC обычно полезен для ввода объекта, который имеет состояние; или классы или интерфейсы, которые имеют более одной реализации, даже если вторая реализация является макетом для целей тестирования. Если ни одно из них не является истинным, вы ничего не получаете, вводя его. самая распространенная идиома в наши дни состоит в том, чтобы ваш класс работал с интерфейсом, который может реализовать реальная и макетная реализация.

1) Статические методы на вспомогательных классах. Нет, они не часто вводятся IoC. Как правило, это утилиты без учета состояния.

Чтобы использовать очень простой пример, вам не нужны две версии утилитного метода StringUtils.Reverse(). Вам нужен только один, и вы можете легко писать тесты вокруг него, потому что у него нет состояния или зависимостей, поэтому нет никакой выгоды издеваться над ним. Пример теста:

string reversedString = StringUtils.Reverse("input");
Assert.AreEqual("tupni", reversedString)

Если утилита на самом деле не является апатридом (например, зависит от HttpContext.Current), то вы должны сделать зависимость явной, введя ее, а не ставить статическую утилиту.

2) Синглтоны: Часто да, впрыскиваются однотонные. Но хорошая вещь в IoC заключается в том, что вы меньше беспокоитесь о том, есть ли только что-то или нет. Вы получаете гибкость при настройке с помощью IoC. Решение о том, что конкретный тип в качестве одиночного или нового экземпляра каждый раз становится частью конфигурации контейнера IoC, и ничто иное в коде не нуждается в изменении.

Таким образом, singleton-hood перестает быть отдельной проблемой, которая должна быть закодирована в классе (и классы, имеющие несколько проблем, когда они не должны быть плохими), и это становится проблемой контейнера IoC. Вы не кодируете класс "как одиночный" с чем-то особенным, как частный конструктор и метод public static GetInstance(), вы просто кодируете его для основной проблемы, в то время как конфиг контейнера IoC указывает, является ли он одиночным или нет, или где-то посередине, как один экземпляр на поток.

3) Статические классы - являются естественным домом для статических методов. При необходимости рассмотрите возможность применения методов расширения статических методов. Вы не можете вводить эти классы, так как вы не можете их создать. Использование статических классов делает для процедурного, а не объектно-ориентированного кода. Это не плохо для небольших вспомогательных методов, но если большая часть кода похожа на это, то вы не используете мощные функции OO платформы .NET.

Ответ 3

Статические методы по определению не нуждаются в экземпляре. DI/IOC стремится удовлетворить интерфейсы с конкретными классами и учитывая, что ваш статический класс вместе со своими статическими методами по определению не может реализовать интерфейс или расширить класс, вопрос не имеет смысла. Нет смысла передавать класс-помощник, потому что для использования статических методов не требуется экземпляр. Вы всегда будете выполнять одни и те же статические методы helperr даже без экземпляра.

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

Ответ 4

Дилемма возникает, когда классы полезности, скажем, нуждаются в базе данных доступа. В то время как db accessor нужен Ioc, таким образом, класс утилиты должен использовать Ioc as, поэтому он не может быть статическим.

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

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

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

Подумайте, почему бы и нет?