Внедрение зависимостей по умолчанию?

Мне нужно регистрировать множество данных по всему моему домену, поэтому большинство служб домена и приложений полагаются на реализацию ведения журналов. Допустим, я создал этот небольшой контракт:

public interface ILogger {

    void Info(string message);

}

Здорово. Теперь я реализовал инфраструктурный сервис на базе log4net:

public class Log4NetProxy : ILogger {

    private ILog _logger = LogManager.GetLogger();

    public void Info(string message) {
        _logger.Info(message);
    }
}

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

public class MyService : IMyService {

    public MyService(ILogger logger, IRepository repo, IAlsoNeedSettings settings) {

    }

}

Как я могу избежать внедрения таких фундаментальных основных требований, как настройки или ведение журнала, и просто сосредоточиться на тех зависимостях, которые мне действительно нужны? Инъекция собственности? Сервисные фасады? Фабрика статических журналов?


person Acrotygma    schedule 13.03.2014    source источник
comment
Посмотрите на аспектно-ориентированное программирование   -  person Sam Leach    schedule 13.03.2014
comment
private ILog _logger = LogManager.GetLogger(); — это сервисный локатор, а не инжектор. Я использую Autofac, но до сих пор не нашел хорошего способа внедрения в графы объектов, не предназначенных для внедрения с нуля (конструктор или свойство/поле); обычно есть какой-то корень, который нуждается в интеграции, а затем, если есть пробелы, может потребоваться открыть контейнер для прямого / SL-разрешения (по крайней мере, до тех пор, пока граф снова не начнет разрешать себя).   -  person user2864740    schedule 13.03.2014
comment
Связано: stackoverflow.com/q/2420193/126014   -  person Mark Seemann    schedule 13.03.2014
comment
Связано: stackoverflow.com/questions /9892137/   -  person Steven    schedule 13.03.2014


Ответы (1)


[Rant+код про перехватчики удален, т.к. это не то, что вам нужно :)]

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

... и я присваиваю сотый ISSomething из значения конструктора свойству...

Я не знаю, как использовать его в Autofac (в основном я использую Castle.Windsor), но я бы рекомендовал его как не требующий особого обслуживания и хороший способ избежать раздувания конструктора.

РЕДАКТИРОВАТЬ: по-видимому, в вопросах, которые Марк Симэнн упоминает, упоминается перехват как допустимый способ обработки этих случаев, поэтому я верну свой исходный код разглагольствований +. Я не уверен, что это соответствует тому, что он имеет в виду, но это может дать вам некоторые идеи.


Мне очень нравится система перехвата Castle-Windsor, которая немного похожа на аспектно-ориентированное программирование, и где вы оборачиваете разрешенные компоненты в перехватчики, которые затем могут решать, как действовать в зависимости от параметров, имени метода и т. д.

вот пример моего регистратора перехвата:

public class LoggingInterceptor: IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        using (Tracer t = new Tracer(string.Format("{0}.{1}", invocation.TargetType.Name, invocation.Method.Name)))
        {
            StringBuilder sb = new StringBuilder(100);
            sb.AppendFormat("IN (", invocation.TargetType.Name, invocation.Method.Name);
            sb.Append(string.Join(", ", invocation.Arguments.Select(a => a == null ? "null" : DumpObject(a)).ToArray()));
            sb.Append(")");
            t.Verbose(sb.ToString());

            invocation.Proceed();

            sb = new StringBuilder(100);
            sb.AppendFormat("OUT {0}", invocation.ReturnValue != null ? DumpObject(invocation.ReturnValue) : "void");
            t.Verbose(sb.ToString());
        }
    }

    private string DumpObject(object argument)
    {
        // serialize object
    }
}

Затем этот перехватчик регистратора регистрируется во время установки и применяется к интересующим классам в службе WCF:

// register interceptors
_container.Register(
    Classes.FromAssemblyInThisApplication()
    .BasedOn<IInterceptor>()
    .WithServiceBase()
    .Configure(c => c.Named(c.Implementation.Name))
);

// apply them
_container.Register
(
    Component.For<IService>()
        .ImplementedBy<ServicesImplementation.Service>()
        .Named("Service")
        .LifestylePerWcfOperation()
        .Interceptors("LoggingInterceptor")
);

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

person samy    schedule 13.03.2014