Создание объекта в рабочем потоке с помощью внедрения зависимостей - PullRequest
0 голосов
/ 02 мая 2018

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

Основываясь на моих исследованиях SO, я заметил, что многие люди предлагают вводить абстрактные фабрики в поток, чтобы динамически создавать потокобезопасный объект в параллельном потоке. 1 , 2

/// <summary>
/// Responsible for starting parallel long running worker threads
/// </summary>
public class ParallelWorkerStarter
{
    private readonly IQueueProcessorFactory _queueProcessorFactory;

    public ParallelWorkerStarter(IQueueProcessorFactory queueProcessorFactory)
    {
        _queueProcessorFactory = queueProcessorFactory;
    }

    public void StartQueueProcessorThread()
    {    
        queueProcessor = new Thread(
        () =>
        {
            _queueProcessorFactory.Create().ProcessQueue();
        })
        { Name = "QueueProcessor" };
        queueProcessor.Start();
    }
}

Абстрактная фабрика для IQueueProcessorFactory выглядит так:

/// <summary>
/// Abstract factory responsible for producing an <see cref="IQueueProcessor"/>
/// </summary>
/// <remarks>
///  This abstract factory is used to generate an <see cref="IQueueProcessor"/> In a seperate thread. 
///  Therefore, all of its dependencies also need to be dynamically generated
/// </remarks>
public interface IQueueProcessorFactory
{
    /// <summary>
    /// Dynamically creates ab <see cref="IQueueProcessor"/>
    /// </summary>
    /// <returns>
    /// The <see cref="IQueueProcessor"/>.
    /// </returns>
    IQueueProcessor Create();
}

Теперь моя основная проблема в том, что конкретный QueueProcessor, который реализует IQueueProcessor, имеет 11 зависимостей (я знаю о запахе кода SRP), и каждая зависимость имеет 5-6 зависимостей.

/// <inheritdoc />
public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventServiceFactory _qeueuedEventServiceFactory;

    private readonly ILoggerFactory _loggerFactory;

    private readonly IEventTriggerActionGroupLogServiceFactory _eventTriggerActionGroupLogServiceFactory;

    private readonly IExceptionLogServiceFactory _exceptionLogServiceFactory;

    private readonly IEventTriggerServiceFactory _eventTriggerServiceFactory;

    private readonly IConditionServiceFactory _conditionServiceFactory;

    private readonly IEventTriggerActionServiceFactory _eventTriggerActionServiceFactory;

    private readonly IEngineEnabledCheckerFactory _engineEnabledCheckerFactory;

    private readonly IEventTriggerScheduleSetServiceFactory _eventTriggerScheduleSetServiceFactory;

    private readonly IEventTriggerActionResultServiceFactory _eventTriggerActionResultServiceFactory;

    private readonly IWorkflowExceptionHandlerFactory _workflowExceptionHandlerFactory;

    public QueueProcessorFactory(
        IEventTriggerQueuedEventServiceFactory qeueuedEventServiceFactory,
        ILoggerFactory loggerFactory,
        IEventTriggerActionGroupLogServiceFactory eventTriggerActionGroupLogServiceFactory,
        IExceptionLogServiceFactory exceptionLogServiceFactory,
        IEventTriggerServiceFactory eventTriggerServiceFactory,
        IConditionServiceFactory conditionServiceFactory,
        IEventTriggerActionServiceFactory eventTriggerActionServiceFactory,
        IEngineEnabledCheckerFactory engineEnabledCheckerFactory,
        IEventTriggerScheduleSetServiceFactory eventTriggerScheduleSetServiceFactory,
        IEventTriggerActionResultServiceFactory eventTriggerActionResultServiceFactory,
        IWorkflowExceptionHandlerFactory workflowExceptionHandlerFactory)
    {
        _qeueuedEventServiceFactory = qeueuedEventServiceFactory;
        _loggerFactory = loggerFactory;
        _eventTriggerActionGroupLogServiceFactory = eventTriggerActionGroupLogServiceFactory;
        _exceptionLogServiceFactory = exceptionLogServiceFactory;
        _eventTriggerServiceFactory = eventTriggerServiceFactory;
        _conditionServiceFactory = conditionServiceFactory;
        _eventTriggerActionServiceFactory = eventTriggerActionServiceFactory;
        _engineEnabledCheckerFactory = engineEnabledCheckerFactory;
        _eventTriggerScheduleSetServiceFactory = eventTriggerScheduleSetServiceFactory;
        _eventTriggerActionResultServiceFactory = eventTriggerActionResultServiceFactory;
        _workflowExceptionHandlerFactory = workflowExceptionHandlerFactory;
    }

    /// <inheritdoc />
    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventServiceFactory.Create(),
            _loggerFactory.Create(),
            _eventTriggerActionGroupLogServiceFactory.Create(),
            _exceptionLogServiceFactory.Create(),
            _eventTriggerServiceFactory.Create(),
            _conditionServiceFactory.Create(),
            _eventTriggerActionServiceFactory.Create(),
            _engineEnabledCheckerFactory.Create(),
            _eventTriggerScheduleSetServiceFactory.Create(),
            _eventTriggerActionResultServiceFactory.Create(),
            _workflowExceptionHandlerFactory.Create());
    }
}

Значит ли это, что мне нужно ~ 60 + абстрактных фабрик, чтобы создать экземпляр моего IQueueProcessor в рабочем потоке? Это звучит как кошмар! Есть ли лучший или более эффективный способ добиться этого?

1 Ответ

0 голосов
/ 02 мая 2018

Значит ли это, что мне нужно ~ 60 + абстрактных фабрик, чтобы создать экземпляр моего IQueueProcessor в рабочем потоке?

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

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

public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventService _qeueuedEventService;    
    private readonly ILogger _logger;    
    private readonly IEventTriggerActionGroupLogService _eventTriggerActionGroupLogService;
    // etc...

    public QueueProcessorFactory(
        IEventTriggerQueuedEventService qeueuedEventService,
        ILogger logger,
        IEventTriggerActionGroupLogService eventTriggerActionGroupLogService,
        /* etc... */)
    {
        _qeueuedEventService = qeueuedEventService;
        _logger = logger;
        _eventTriggerActionGroupLogService = eventTriggerActionGroupLogService;
        // etc...
    }

    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventService,
            _logger,
            _eventTriggerActionGroupLogService,
            /* etc... */);
    }
}

В действительности вам может потребоваться смешать некоторые переходные зависимости (для этого потребуются фабрики) с некоторыми зависимостями Singleton.

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

Кроме того, вам не нужно определять интерфейс для каждой зависимости, но вместо этого можно рассмотреть использование универсального интерфейса, такого как:

public interface IFactory<T>
{
    T Create();
}

Опять же, некоторые из DI-контейнеров поддерживают такие фабрики. Вы также можете полностью отказаться от интерфейса и просто использовать делегат, такой как Func<T>.

Однако, если обстоятельства не являются особенными, я не рекомендую DI-контейнер, а скорее рекомендую Pure DI . Когда вы используете DI-контейнер, вы теряете безопасность во время компиляции, что, как я думаю, не стоит компромисса; в конце концов, узким местом программирования редко является скорость печати. ​​

...