Подтвердить что ты не робот

Какой шаблон использовать для ведения журнала? Инъекция зависимостей или локатор обслуживания?

Рассмотрим этот сценарий. У меня есть некоторая бизнес-логика, которую время от времени потребуется писать в журнал.

interface ILogger
{
    void Log(string stuff);
}

interface IDependency
{
    string GetInfo();
}

class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)
    {
        _dependency = dependency;
    }

    public string DoSomething(string input)
    {
        // Process input
        var info = _dependency.GetInfo();
        var intermediateResult = PerformInterestingStuff(input, info);

        if (intermediateResult== "SomethingWeNeedToLog")
        {
            // How do I get to the ILogger-interface?
        }

        var result = PerformSomethingElse(intermediateResult);

        return result;
    }
}

Как вы получите интерфейс ILogger? Я вижу две основные возможности:

  • Передайте его, используя Injection Dependency в конструкторе.
  • Получите его через одноранговый сервисный локатор.

Какой метод вы бы предпочли, и почему? Или есть еще лучший образец?

Update: Обратите внимание, что мне не нужно регистрировать ВСЕ вызовы методов. Я хочу только регистрировать несколько (редких) событий, которые могут возникнуть или не произойти в моем методе.

4b9b3361

Ответ 1

Я лично делаю смесь обоих.

Вот мои соглашения:

  • Из статического контекста - Местоположение службы
  • Из контекста экземпляра - Инъекция зависимостей

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

Некоторые из них выразили обеспокоенность в связи с тем, что DI стремится к созданию конструкторов. Я не чувствую, что это проблема, но если вы так себя чувствуете, существует ряд альтернатив, которые используют DI, но избегайте параметров конструктора. Вот список методов Ninject DI: http://ninject.codeplex.com/wikipage?title=Injection%20Patterns

Вы обнаружите, что большинство контейнеров Inversion of Control имеют те же функции, что и Ninject. Я решил показать Ninject, потому что у них самые сжатые образцы.

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

Изменить: Чтобы быть ясным, я использую Unity и Common Service Locator. У меня есть экземпляр singleton моего контейнера Unity для DI, и моя реализация IServiceLocator - это просто обертка вокруг этого контейнера Singleton Unity. Таким образом, мне не нужно делать какие-либо сопоставления типов дважды или что-то в этом роде.

Я также не считаю, что AOP особенно полезно для отслеживания. Мне нравится ручная регистрация лучше просто для ее ясности. Я знаю, что большинство протоколов регистрации АОП способны к обоим, но я не нуждаюсь в первом (AOP-хлеб и масло) большую часть времени. Это, конечно, личное предпочтение.

Ответ 2

Логгер, безусловно, является сервисом, от которого зависит ваша бизнес-логика, и поэтому его следует рассматривать как зависимость так же, как и с IDependency. Внесите регистратор в свой конструктор.

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

Ответ 3

Мы переключили все атрибуты Logging/Tracing в PostSharp (AOP framework). Все, что вам нужно сделать для создания журнала для метода, - это добавить к нему атрибут.

Преимущества:

  • Простое использование AOP
  • Очистить разделение проблем
  • Происходит при времени компиляции Минимальное воздействие на производительность

Отметьте этот.

Ответ 4

Мое маленькое эмпирическое правило:

  • Если это в библиотеке классов, используйте либо инъекцию конструктора, либо инъекцию свойства с шаблоном нулевого объекта.

  • Если он используется в основном приложении, используйте локатор службы (или singleton).

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

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

YMMV, конечно. DI отлично, но это не значит, что все должно быть выполнено.

Ответ 5

Вы можете получить другой тип, например. LoggableBusinessObject, который принимает логгер в своем конструкторе. Это означает, что вы только проходите в журнале для объектов, которые будут его использовать:

public class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)   
    {   
        _dependency = dependency;   
    }   

    public virtual string DoSomething(string input)   
    {   
        // Process input   
        var info = _dependency.GetInfo();   
        var result = PerformInterestingStuff(input, info);   
        return result;   
    }   
}

public class LoggableBusinessObject : MyBusinessObject
{
    private ILogger _logger;

    public LoggableBusinessObject(ILogger logger, IDependency dependency)
        : base(dependency)
    {
        _logger = logger;
    }

    public override string DoSomething(string input)
    {
        string result = base.DoSomething(input);
        if (result == "SomethingWeNeedToLog")
        {
             _logger.Log(result);
        }
    }
}

Ответ 6

Может быть, это будет немного оффтопным, но зачем нам вообще вводить регистратор, когда мы можем просто набрать начало в классе:

Logger logger = LogManager.GetLogger("MyClassName");

Логгер не изменяется во время разработки, а затем во время обслуживания. Современные регистраторы очень настраиваемые, поэтому аргумент

Что делать, если я хочу заменить текстовый регистратор на базу данных?

пропущено.

Я не отрицаю использование инъекции зависимостей, мне просто интересно узнать о вашем уме.

Ответ 7

DI будет работать хорошо здесь. Еще одна вещь, на которую нужно обратить внимание: AOP.

Ответ 8

Я бы не рекомендовал ни один из этих подходов. Лучше использовать аспектно-ориентированное программирование. Регистрация - это "мир привет" АОП.

Ответ 9

Я бы предпочел Singleton Service.

Включение зависимостей будет загромождать конструктор.

Если вы можете использовать AOP, это было бы лучше.